home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.0_SDK / Source / FWiX / FWiXApp / FWiXmain.c < prev    next >
Encoding:
Text File  |  1999-04-12  |  90.4 KB  |  3,665 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FWiXMain.c
  3.  
  4.     Contains:    Application software to transfer files over FireWire.
  5.  
  6.     Version:    1.0
  7.  
  8.     Written by:    Jay Lloyd
  9.     
  10.     Copyright:    © 1996-1999 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     File Ownership:
  13.  
  14.         DRI:                Jay Lloyd
  15.  
  16.         Other Contact:        
  17.  
  18.         Technology:            FireWire
  19.  
  20.     Writers:
  21.  
  22.         (DCB)    Clinton Bauder
  23.         (jkl)    Jay Lloyd
  24.  
  25.     Change History (most recent first):
  26.  
  27.       <FW37>      2/2/99    DCB        Fix for latest MI headers.
  28.       <FW36>    12/19/98    DCB        More cleanup for SDK.
  29.       <FW35>     7/24/98    jkl        Removed page alignment of data buffers.
  30.       <FW34>     7/22/98    jkl        Call CreateMenus before InitPrefs. InitPrefs tries to adjust a
  31.                                     menu item name.
  32.         <33>     1/15/98    jkl        Update for new headers.
  33.       <FW32>     6/19/97    jkl        Added support for GetNodeList and SendItems AppleScript
  34.                                     commands. Saved the icons view as a preference. Updated the open
  35.                                     sharing setup command for Tempo to open File Sharing .
  36.       <FW31>     6/10/97    jkl        Made sure a device added message does not result in the same
  37.                                     device getting added twice.
  38.       <FW30>     5/28/97    jkl        Made sure send or receive error is cleared before calling error
  39.                                     dialog. The not cleared error could cause the dialog to
  40.                                     repeatedly display itself.
  41.       <FW29>     5/27/97    jkl        Changed memory allocation for data buffers to ensure they are on
  42.                                     4k boundaries.
  43.       <FW28>     5/16/97    jkl        Corrected some GetPort SetPort bracketing around updates and
  44.                                     drawing.
  45.       <FW27>     5/15/97    jkl        Modified error handling routines to recover from errors during
  46.                                     the transfer check before file sending has started. Held all of
  47.                                     the completion routines.
  48.       <FW26>      5/7/97    jkl        Modified linked lists to double linked lists to simplify
  49.                                     insertion and deletion of list items.
  50.       <FW25>     4/29/97    jkl        Fixed main symbol export. Made sure drop folder exsists before
  51.                                     calling open drop folder routine.
  52.       <FW24>     4/29/97    jkl        Added global alert routine to handle alert event filters.
  53.                                     Corrected a problem that could leave the connected fwix machine
  54.                                     list corrupted.
  55.       <FW23>      4/8/97    jkl        Added page up/down, home, and end key scrolling support. Changed
  56.                                     my BBS initials to not conflict with Jim Luther's.
  57.       <FW22>     3/18/97    jkl        Added new icons. Changed text drawing to use TETextBox. Moved
  58.                                     prefs related routines to prefs.c.
  59.       <FW21>     2/27/97    jkl        Modified preferences to be under receiver control and removed
  60.                                     prompt preference. Added Edit menu and moved Preferences command
  61.                                     to there. Added support for scrolling the sender window.
  62.       <FW20>     2/21/97    jkl        Changed icon placement and management in sender window for
  63.                                     better multiple node support. Updated preferences menu to handle
  64.                                     menus and sound popup correctly.
  65.       <FW19>     2/19/97    jkl        Added Reply/Request options to SendFWXInfo. Set the state of the
  66.                                     sound notification popup menu according to the play sound check
  67.                                     box. Added play the sound after it is selected in the popup.
  68.                                     Corrected window zoom states. Made sure notification resources
  69.                                     are not purgeable.
  70.       <FW18>     2/13/97    jkl        Added a ForkWriteComplete to make sure a data buffer is
  71.                                     available before starting to read a new file fork.
  72.       <FW17>     2/11/97    jkl        Added read control and read data buffers and queues. Moved fwix
  73.                                     preferences to a file and closed file in all cases. Fixed
  74.                                     buttons in no sharing name dialog.
  75.       <FW16>     2/10/97    ES        Cleaned up deallocation code. Removed system heap allocations.
  76.       <FW15>      2/7/97    ES        Added call to GetNextFWXClientEvent in event loop.
  77.       <FW14>      2/6/97    ES        Changed to maintain list of all nodes that have been opened.
  78.                                     Will send quit notification to and close all nodes that have
  79.                                     been opened when quitting.
  80.       <FW13>      2/5/97    ES        Changed a CloseFWXDriver to CloseFWXNode.
  81.       <FW12>      2/2/97    jkl        Added Open Sharing Setup command to no machine name alert.
  82.                                     Modified menus and corrected menu state enabled/disabled
  83.                                     problems. Changed open drop folder command to make the finder
  84.                                     the foreground process. Corrected view size menu commands to
  85.                                     only work if that size is not the current size. Move the
  86.                                     preferences to a file. Correct the flahsing icon notification.
  87.                                     Moved NewPtrSys calls that are safe back to NewPtr.
  88.       <FW11>     1/29/97    ES        Changed InstallCompletionRoutineProcs to set up completion
  89.                                     routines to return status in D0. This is a workaround for a bug
  90.                                     in the File Manager.
  91.       <FW10>     1/27/97    ES        Added creation of FWControl PB queue.
  92.        <FW9>     1/27/97    jkl        Added timer routines to check for transfer disconnects and
  93.                                     errors. At idle check for timeout errors. Cleaned up from a
  94.                                     device removed event properly if a transfer is in progress.
  95.                                     Removed killio routine from CloseWindow, will let closing the
  96.                                     node handle it. Added check for transmit in progress and option
  97.                                     to quit or continue. Fixed stop button in progress dialog by
  98.                                     adding setport call. Modified view options menu to show check
  99.                                     marks instead of toggle title.
  100.        <FW8>     1/17/97    ES        Changed a CallFWXDriver to CallFWXNode. Changed NewPtrs to
  101.                                     NewPtrSyss because some buffers need to be held to be VM safe;
  102.                                     this is overkill, and really we just need to hold the right
  103.                                     buffers. Used NewPtrSysClear to allocate pRecvNode so that its
  104.                                     next pointer is nil.
  105.        <FW7>     1/16/97    jkl        Removed an open DebugStr call.
  106.        <FW6>     1/16/97    jkl        Added user interface features for alpha candidate. Added a
  107.                                     preferences dialog, changed window behavior to match normal
  108.                                     window behavior, changed fwix node icons to only be displayed if
  109.                                     the node has fwix running. Added receive file notification.
  110.        <FW5>      1/8/97    ES        Changed to use FWX nodes instead of FWX drivers. Fixed up hot
  111.                                     plugging and unplugging.
  112.        <FW4>    11/13/96    jkl        Moved from DoDriverIO interface to CallDriver. Implemented stop
  113.                                     transfer. Now Indentify receivers by name.
  114.        <FW3>     10/31/96    jkl        Fixed event handling when copy progress dialog
  115.                                        is being displayed. Added routine to update copy
  116.                                     progress dialog at idle time. Moved receive folder
  117.                                     check and initialization to application init time.
  118.        <FW2>     10/16/96    jkl        Modified queue handling to use OS Utils interrupt
  119.                                        safe queue routines. Created File Write Completion
  120.                                     routine proc. Removed reads and writes from idle
  121.                                     handler. The idle handler only checks to see if
  122.                                     the read or write is done. The reads and writes
  123.                                     are continued in the various completion routines.
  124.        <FW1>     10/2/96    jkl        Initial check-in.
  125. */
  126.  
  127. #include <QuickDraw.h>
  128. #include <SegLoad.h>
  129. #include <Types.h>
  130. #include <Memory.h>
  131. #include <Resources.h>
  132. #include <Fonts.h>
  133. #include <Controls.h>
  134. #if !ETO_Build
  135. #include <ControlDefinitions.h>
  136. #endif
  137. #include <Menus.h>
  138. #include <Dialogs.h>
  139. #include <Events.h>
  140. #include <AppleEvents.h>
  141. #include <Processes.h>
  142. #include <Windows.h>
  143. #include <Errors.h>
  144. #include <Files.h>
  145. #include <Folders.h>
  146. #include <Script.h>
  147. #include <Devices.h>
  148. #include <TextUtils.h>
  149. #include <ToolUtils.h>
  150. #include <StandardFile.h>
  151. #include <Icons.h>
  152. #include <DiskInit.h>    
  153. #include <Notification.h>
  154. #include <Timer.h>
  155. #include <Sound.h>
  156.  
  157. #include "FWiX.h"
  158.  
  159. #include "FWiXmain.h"
  160. #include "FWiXdrag.h"
  161.  
  162. #include <stdio.h>
  163. char  debugStr[256];
  164. static pascal void FWDebugStr(
  165.     ConstStr255Param            debuggerMsg)
  166. {
  167. #ifdef FW_DEBUG_BUILD
  168. #if FW_DEBUG_BUILD
  169.     DebugStr (debuggerMsg);
  170. #endif
  171. #endif
  172. }
  173.  
  174. //////////////////////////////////////////////////////////////////////////////
  175. //
  176. // Internal procedure prototypes.
  177. //
  178.  
  179. static OSErr SendDeviceAddedToSelf (
  180.     FWXNodeID                theNodeID);
  181.  
  182. static OSErr SendDeviceRemovedToSelf (
  183.     FWXNodeID                theNodeID);
  184.     
  185. static pascal OSErr    HandleDeviceAddedEvent (
  186.     AppleEvent                *theAppleEvent,
  187.     AppleEvent                *reply,
  188.     SInt32                    handlerRefcon);
  189.  
  190. static OpenNodePtr GetNodeInfoFromID (
  191.     FWXNodeID                nodeID);
  192.  
  193. static pascal OSErr    HandleDeviceRemovedEvent (
  194.     AppleEvent                *theAppleEvent,
  195.     AppleEvent                *reply,
  196.     SInt32                    handlerRefcon);
  197.     
  198. void AdjustNodeIcons (
  199.     WindowDataPtr            pWinData,
  200.     Rect                    *windRect);
  201.  
  202. OSErr SendFWXInfo (
  203.     FWXNodeID                nodeID,
  204.     UInt32                    sendType);
  205.  
  206. OSErr SendFWXQuit (void);
  207.  
  208. static OSErr SetupFWXRead (
  209.     FWXNodeID                nodeID);
  210.  
  211. static OSErr GetNodeIDFromEvent (
  212.     AppleEvent                *pEvent,
  213.     FWXNodeID                *nodeID);
  214.     
  215. static OSErr GetNodeIDFromName (
  216.     FWXNodeID                *nodeID,
  217.     ConstStr255Param        nodeName);
  218.  
  219. static OSErr NewSenderWindow (void);
  220.  
  221. static void GetDisplayRect (
  222.     Rect                    *r,
  223.     WindowPtr                pWin,
  224.     WindowDataPtr            pWinData);
  225.  
  226. OSErr AdjustScrollBars (
  227.     WindowPtr                pWin,
  228.     Boolean                    adjustSizes);
  229.  
  230. OSErr InitRecvNode (
  231.     FWXNodeID                nodeID,
  232.     ConstStr255Param        nodeName);
  233.     
  234. static pascal void HandleReplyTimeout (
  235.     MyTMTaskPtr            pTMTask);
  236.  
  237. static pascal OSErr HandleGetNodeListEvent (
  238.     AppleEvent                *pAppleEvent,
  239.     AppleEvent                *pReplyEvent,
  240.     SInt32                    refCon);
  241.  
  242. static pascal OSErr HandleSendItemsEvent (
  243.     AppleEvent                *pAppleEvent,
  244.     AppleEvent                *pReplyEvent,
  245.     SInt32                    refCon);
  246.     
  247. static OSErr GetFSItemsFromEvent (
  248.     FSSpecPtr                *pSendItems,
  249.     AppleEvent                *pEvent,
  250.     UInt16                    *numItems);
  251.  
  252. static OSErr GetReceiveNodesFromEvent (
  253.     FWXNodeID                **pReceiveNodeIDList,
  254.     AppleEvent                *pAppleEvent,
  255.     UInt16                    *numNodes);
  256.     
  257. static pascal OSErr HandleOpenApplicationEvent (
  258.     AppleEvent                *pAppleEvent,
  259.     AppleEvent                *pReplyEvent,
  260.     SInt32                    refCon);
  261.     
  262. static pascal OSErr HandleOpenDocumentsEvent (
  263.     AppleEvent                *pAppleEvent,
  264.     AppleEvent                *pReplyEvent,
  265.     SInt32                    refCon);
  266.     
  267. static pascal OSErr HandleQuitApplicationEvent (
  268.     AppleEvent                *pAppleEvent,
  269.     AppleEvent                *pReplyEvent,
  270.     SInt32                    refCon);
  271.     
  272. static OSErr InstallAppleEventHandlers (void);
  273.  
  274. static OSErr InstallCompletionRoutineProcs (void);
  275.  
  276. static void DrawWindow (
  277.     WindowPtr                pWin);
  278.  
  279. static OSErr CreateMenus (void);
  280.  
  281. static void HandleCloseWindow (
  282.     WindowPtr                pWin);
  283.     
  284. static void HandleQuit (void);
  285.  
  286. static void HandleMenuCommand (
  287.     SInt32                    menuVal);
  288.     
  289. OSErr OpenDropFolder(void);
  290.  
  291. static OSErr OpenSharingSetup(void);
  292.  
  293. static OSErr HandleViewSize(
  294.     SInt16                    menuItem);
  295.  
  296. static void HandleMouseDownEvent (
  297.     EventRecord                *pEventRecord);
  298.  
  299. static pascal void HandleThumbScroll (
  300.     ControlHandle            scrollCtl,
  301.     WindowPtr                pWin,
  302.     Point                    mouse);
  303.  
  304. static pascal void HandleScrollAction (
  305.     ControlHandle            scrollCtl,
  306.     SInt16                    part);
  307.  
  308. static void HandleGrowWindow(
  309.     WindowPtr                    pWin,
  310.     Point                        clickLoc);
  311.  
  312. static void HandleZoomWindow(
  313.     WindowPtr                    pWin,
  314.     SInt16                        whichZoom);
  315.  
  316. void StopTransfer (
  317.     RecvNodePtr                    pNode);
  318.  
  319. static void HandleKeyEvent (
  320.     EventRecord                *pEventRecord);
  321.  
  322. static void HandleOSEvent (
  323.     EventRecord                *pEventRecord);
  324.  
  325. static void HandleEvent (
  326.     EventRecord                *theEvent);
  327.  
  328. static void HandleActivate (
  329.     WindowPtr                pWin,
  330.     Boolean                    becomingActive);
  331.  
  332. static Boolean IsAppWindow (
  333.     WindowPtr                pWin);
  334.     
  335. static pascal Boolean HandleAlertEventFilter (
  336.     DialogPtr                pDlog,
  337.     EventRecord                *pEvent,
  338.     SInt16                    *itemHit);
  339.  
  340. static OSErr SetupFWXNode (void);
  341.  
  342. static OSErr InitNotification (void);
  343.  
  344. pascal void HandleNotifyResponse (
  345.     NMRecPtr                pNMRequest);
  346.  
  347.  
  348. static OSErr SetupIOQueue (void);
  349.  
  350. static OSErr FWXInit (void);
  351.     
  352. static OSErr FWXDispose (void);
  353.  
  354. //////////////////////////////////////////////////////////////////////////////
  355. //
  356. // External procedure prototypes.
  357. //
  358.  
  359. extern OSErr InstallDragHandlers (void);    
  360.  
  361. extern void RemoveDragHandlers (void);
  362.     
  363. extern pascal OSErr HandleAEFileSpecList (
  364.     AppleEvent                *pAEvent,
  365.     AppleEvent                 *pReply,
  366.     SInt32                    refCon);
  367.  
  368. extern OSErr GetNodeDragRect (
  369.     WindowPtr                pWin,
  370.     SInt16                    spaceIndex,
  371.     Rect                    *iconRect,
  372.     Rect                    *textRect);
  373.  
  374. extern void HandleReceive (void);
  375.  
  376. extern void HandleForkReadComplete (void);
  377.  
  378. extern OSErr FSGetCatInfo (
  379.     FSSpec                     *fsSpec,
  380.     CInfoPBPtr                result);
  381.  
  382. extern void UpdateProgressBar (
  383.     WindowPtr            theWindow,
  384.     SInt16                itemNo);
  385.  
  386. extern OSErr GetNodeName (
  387.     WindowPtr            pWin,
  388.     SInt16                spaceIndex,
  389.     StringPtr            *pString);
  390.     
  391. extern void CleanupCopyDialog(
  392.     WindowPtr            theDialog);
  393.  
  394. extern OSErr GetNodeInfo (
  395.     FWXNodeID            nodeID,
  396.     RecvNodePtr            *pRecvNode);
  397.  
  398. extern OSErr HandleStopTransfer(
  399.     CurFileInfoPtr        pCurFileInfo);
  400.     
  401. extern OSErr GetCurFileInfo(
  402.     FWXNodeID            sourceID,
  403.     CurFileInfoPtr        *hCurFileInfo,
  404.     Boolean                createNew);
  405.  
  406. extern OSErr InitRecvFolder(
  407.     SInt32                *dirID);
  408.  
  409.  
  410. //////////////////////////////////////////////////////////////////////////////
  411. //
  412. //    Globals JKL *** these all need to be cleaned up
  413. //
  414. #ifndef __MWERKS__
  415. QDGlobals            qd;
  416. #endif
  417.  
  418. FWXAppDataPtr        gpFWXAppData = nil;
  419.  
  420. Boolean                queuesInitialized = false;
  421. QHdr                gSendQHdr;
  422. QHdr                gAESendQHdr;
  423. QHdr                gReceiveQHdr;
  424. QHdr                gFileReadQHdr;
  425. QHdr                gFWControlQHdr;
  426. QHdr                gFWWriteQHdr;
  427. QHdr                gCurFileQHdr;
  428. SInt16                gCurForkRefNum;
  429.  
  430. Boolean             gSendingFile,
  431.                     gCheckingTransfer,
  432.                     gSendingDataFork,
  433.                     gSendingResFork,
  434.                     gForkWriteComplete,
  435.                     gForkComplete;
  436.  
  437. FWXNodeID    gSendError;
  438. FWXNodeID    gReceiveError;
  439.                     
  440. //////////////////////////////////////////////////////////////////////////////
  441. //
  442. //    SendDeviceAddedToSelf
  443. //
  444. //    Send a firewire device added appleevent to us
  445. //
  446. static OSErr SendDeviceAddedToSelf(
  447.     FWXNodeID                theNodeID)
  448. {
  449.     AppleEvent                send;
  450.     AppleEvent                reply;
  451.     AEDesc                    selfTarget;
  452.     ProcessSerialNumber        psn;
  453.     OSErr                    err;
  454.  
  455.     selfTarget.dataHandle = nil;
  456.     send.dataHandle = nil;
  457.  
  458.     // Get our address
  459.     GetCurrentProcess(&psn);
  460.     err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &selfTarget);
  461.     if (err != noErr)
  462.         return err;
  463.             
  464.     err = AECreateAppleEvent(kAEFWXEventClass, kAEFWXDeviceAdded, &selfTarget, 
  465.             kAutoGenerateReturnID, kAnyTransactionID, &send);
  466.     if (err != noErr) {
  467.         AEDisposeDesc(&selfTarget);
  468.         return err;
  469.     }
  470.     
  471.     err = AEPutParamPtr(&send, kAEFWXNodeIDKey, kAEFWXNodeIDType, (Ptr) &theNodeID, sizeof(FWXNodeID));
  472.  
  473.     err = AESend(&send, &reply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  474.                 kAENormalPriority, kAEDefaultTimeout, nil, nil);
  475.  
  476.     if (err != noErr) {
  477.         AEDisposeDesc(&selfTarget);
  478.         AEDisposeDesc(&send);
  479.     }
  480.  
  481.     return err;
  482. }
  483.  
  484. //////////////////////////////////////////////////////////////////////////////
  485. //
  486. //    SendDeviceRemovedToSelf
  487. //
  488. //    Send a firewire device removed appleevent to us
  489. //
  490. static OSErr SendDeviceRemovedToSelf(
  491.     FWXNodeID                theNodeID)
  492. {
  493.     AppleEvent                send;
  494.     AppleEvent                reply;
  495.     AEDesc                    selfTarget;
  496.     ProcessSerialNumber        psn;
  497.     OSErr                    err;
  498.  
  499.     selfTarget.dataHandle = nil;
  500.     send.dataHandle = nil;
  501.  
  502.     // Get our address
  503.     GetCurrentProcess(&psn);
  504.     err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &selfTarget);
  505.     if (err != noErr)
  506.         return err;
  507.             
  508.     err = AECreateAppleEvent(kAEFWXEventClass, kAEFWXDeviceRemoved, &selfTarget, 
  509.             kAutoGenerateReturnID, kAnyTransactionID, &send);
  510.     if (err != noErr) {
  511.         AEDisposeDesc(&selfTarget);
  512.         return err;
  513.     }
  514.         
  515.     err = AEPutParamPtr(&send, kAEFWXNodeIDKey, kAEFWXNodeIDType, (Ptr) &theNodeID, sizeof(FWXNodeID));
  516.  
  517.     err = AESend(&send, &reply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  518.                 kAENormalPriority, kAEDefaultTimeout, nil, nil);
  519.  
  520.     if (err != noErr) {
  521.         AEDisposeDesc(&selfTarget);
  522.         AEDisposeDesc(&send);
  523.     }
  524.     
  525.     return err;
  526. }
  527.  
  528. //////////////////////////////////////////////////////////////////////////////
  529. //
  530. //    HandleDeviceAddedEvent
  531. //
  532. //    Called when a new FireWire File Exchange receiver connects to the bus.
  533. //    Add it to the list of open nodes. Prime it with receive buffers. Send our
  534. //    machine info to it.
  535. //
  536. static pascal OSErr    HandleDeviceAddedEvent (
  537.     AppleEvent            *theAppleEvent,
  538.     AppleEvent            *reply,
  539.     long                handlerRefcon)
  540. {
  541.     WindowPtr            pWin;
  542.     WindowDataPtr        pWinData;
  543.     OpenNodePtr            pOpenNode;
  544.     OpenNodePtr            pTempOpenNode;
  545.     FWXNodeID            nodeID;
  546.     OSErr                err = noErr;
  547.     
  548.     //    get node id out of appleevent
  549.     err = GetNodeIDFromEvent(theAppleEvent, &nodeID);
  550.         
  551.     if (err == noErr)
  552.         pOpenNode = GetNodeInfoFromID(nodeID);
  553.     
  554.     if ((err == noErr) && (pOpenNode == nil))
  555.     {
  556.         pWin = gpFWXAppData->pSenderWindow;
  557.         pWinData = (WindowDataPtr) GetWRefCon(pWin);
  558.         if (pWinData == nil)
  559.             err = memFullErr;
  560.         
  561.         if (err == noErr)
  562.         {
  563.             // create open node record.
  564.             pOpenNode = (OpenNodePtr) NewPtrClear(sizeof(OpenNodeRecord));
  565.             if (pOpenNode != nil)
  566.                 pOpenNode->nodeID = nodeID;
  567.             else
  568.                 err = memFullErr;
  569.         }
  570.             
  571.         if (err == noErr)
  572.             // open the node
  573.             err = OpenFWXNode(nodeID);
  574.                 
  575.         if (err == noErr)
  576.         {
  577.             pWinData->numOpenNodes++;
  578.         
  579.             // add the node to the open list
  580.             // if this is the first node, just point to it
  581.             if (pWinData->numOpenNodes == 1)
  582.                 pWinData->pOpenNodeList = pOpenNode;
  583.             else
  584.             {
  585.                 // it is not the first node, traverse the list, add new node to the end
  586.                 pTempOpenNode = pWinData->pOpenNodeList;
  587.                 while (pTempOpenNode->pNextNode != nil)            
  588.                     pTempOpenNode = pTempOpenNode->pNextNode;
  589.                 pTempOpenNode->pNextNode = pOpenNode;
  590.                 pOpenNode->pPreviousNode = pTempOpenNode;
  591.             }
  592.         }
  593.  
  594.         if (err != noErr)
  595.         {
  596.             // clean up on error
  597.             if (pOpenNode != nil)
  598.                 DisposePtr((Ptr) pOpenNode);
  599.         }
  600.  
  601.         if (err == noErr)
  602.             // issue reads to prime node with receive buffers
  603.             err = SetupFWXRead(nodeID);
  604.             
  605.         if (err == noErr)
  606.             // send the new node our name and id info
  607.             err = SendFWXInfo(nodeID, kNodeInfoRequest);
  608.     
  609.         if (err == memFullErr)
  610.             HandleStopAlert(kMemoryErrorAlertID);
  611.         else if (err != noErr)
  612.             // JKL *** need a generic error alert mechanism
  613.             HandleStopAlert(kUnknownErrAlertID);
  614.     }
  615.     return err;
  616. }
  617.  
  618. ////////////////////////////////////////////////////////////////////////////////
  619. //
  620. //    GetNodeInfoFromID
  621. //
  622. //    Search open node list for node record corresponding to node id.
  623. //
  624. static OpenNodePtr GetNodeInfoFromID (
  625.     FWXNodeID            nodeID)
  626. {
  627.     WindowDataPtr        pWinData;
  628.     OpenNodePtr            pOpenNode;
  629.     Boolean                found;
  630.     
  631.     pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  632.     pOpenNode = pWinData->pOpenNodeList;
  633.  
  634.     found = false;
  635.     while ((pOpenNode != nil) && (!found))
  636.     {
  637.         if (pOpenNode->nodeID == nodeID)
  638.             found = true;
  639.         else
  640.             pOpenNode = pOpenNode->pNextNode;
  641.     }
  642.     return pOpenNode;
  643. }
  644.  
  645. ////////////////////////////////////////////////////////////////////////////////
  646. //
  647. //    SendFWXInfo
  648. //
  649. //    Send our info to another node. Get the sharing setup machine name out
  650. //    of string resource.
  651. //
  652. OSErr SendFWXInfo(
  653.     FWXNodeID            nodeID,
  654.     UInt32                sendType)
  655. {
  656.     Handle                hString;
  657.     IOParamPtr            pIOPb;
  658.     FWXPacketPtr        pPktInfo;
  659.     SInt16                curResFile;
  660.     OSErr                err = noErr;
  661.  
  662.     // Get the sharing setup macintosh name
  663.     curResFile = CurResFile();
  664.     UseResFile(kSystemResFile);
  665.     hString = Get1Resource('STR ', kNetworkNameID);
  666.  
  667.     if ((hString != nil) && (**hString != 0))
  668.     {
  669.         FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  670.         if (pIOPb != nil)
  671.         {
  672.             SetupFWControlPB(pIOPb);
  673.             // SetupFWControlPB will leave an invalid node id in nameptr at this point
  674.             pIOPb->ioNamePtr = (StringPtr) nodeID;
  675.             
  676.             // copy the string into the data buffer
  677.             pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  678.             pPktInfo->packetType = sendType;
  679.             pIOPb->ioMisc = (Ptr) sendType;
  680.             BlockMove(*hString, (Ptr) &pPktInfo->packetData, **hString + 1);
  681.             pIOPb->ioReqCount = **hString + 1 + 4;    // length of string plus packet header
  682.             
  683.             err = CallFWXNode(pIOPb);
  684.         }
  685.         else
  686.         {
  687.             err = qErr;
  688.             FWDebugStr("\pNo buffer for SendFWXInfo");
  689.         }
  690.  
  691.         ReleaseResource(hString);
  692.     }
  693.     else
  694.     {
  695.         HandleStopAlert(kNoNameAlertID);
  696.         ExitToShell();
  697.     }
  698.     UseResFile(curResFile);
  699.     return err;
  700. }
  701.  
  702. ////////////////////////////////////////////////////////////////////////////////
  703. //
  704. //    SendFWXQuit
  705. //
  706. //    Send a quit notification to each receive node.
  707. //
  708. OSErr SendFWXQuit(void)
  709. {
  710.     WindowDataPtr        pWinData;
  711.     OpenNodePtr            pOpenNode;
  712.     IOParamPtr            pIOPb;
  713.     FWXPacketPtr        pPktInfo;
  714.     SInt16                i;
  715.     OSErr                err = noErr;
  716.  
  717.     pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  718.     if (pWinData != nil)
  719.     {        
  720.         pOpenNode = pWinData->pOpenNodeList;
  721.         for (i = 0; i < pWinData->numOpenNodes; i++)
  722.         {
  723.             FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  724.             if (pIOPb != nil)
  725.             {
  726.                 SetupFWControlPB(pIOPb);
  727.                 // SetupFWWritePB will leave an invalid driver id in nameptr at this point
  728.                 pIOPb->ioNamePtr = (StringPtr) pOpenNode->nodeID;
  729.                 
  730.                 // copy the string into the data buffer
  731.                 pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  732.                 pPktInfo->packetType = kQuitNotify;
  733.                 pIOPb->ioMisc = (Ptr) kQuitNotify;
  734.                 pIOPb->ioReqCount = 4;
  735.                 
  736.                 err = CallFWXNode(pIOPb);
  737.             }
  738.             else
  739.             {
  740.                 err = qErr;
  741.                 FWDebugStr("\pNo buffer for SendFWXQuit");
  742.             }
  743.             pOpenNode = (OpenNodePtr) pOpenNode->pNextNode;
  744.         }
  745.     }
  746.     else
  747.         err = resNotFound;
  748.  
  749.     return err;
  750. }
  751.  
  752. ////////////////////////////////////////////////////////////////////////////////
  753. //
  754. //    SetupFWXRead
  755. //
  756. //    Create control buffers and a data buffer and pass the buffers to
  757. //    the driver.
  758. //
  759. static OSErr SetupFWXRead(
  760.     FWXNodeID            nodeID)
  761. {
  762.     IOParamPtr            pIOPb;
  763.     SInt16                i;
  764.     OSErr                err = noErr;
  765.  
  766.     // create control receive parameter block, receive buffer, and issue read
  767.     for (i=0; i < kFWReadControlBufs; i++) {
  768.         pIOPb = (IOParamPtr) NewPtrClear(sizeof(IOParam));
  769.         if (pIOPb != nil) {
  770.             HoldMemory ((Ptr) pIOPb, sizeof(IOParam));
  771.         } else {
  772.             FWDebugStr("\pOut of memory, SetupReadQueue");
  773.             err = memFullErr;
  774.             break;
  775.         }
  776.         
  777.         pIOPb->ioBuffer = NewPtr(kFWReadControlBufSize);
  778.         if (pIOPb->ioBuffer != nil) {
  779.             HoldMemory (pIOPb->ioBuffer, kFWReadControlBufSize);
  780.         } else {
  781.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  782.             DisposePtr((Ptr) pIOPb);
  783.             FWDebugStr("\pOut of memory, SetupReadQueue");
  784.             err = memFullErr;
  785.             break;
  786.         }
  787.         
  788.         // set up parameter block
  789.         pIOPb->ioNamePtr = (StringPtr) nodeID;
  790.         pIOPb->ioTrap = kFWXRead;
  791.         pIOPb->ioCompletion = (IOCompletionUPP) HandleFWReadComplete;
  792.         pIOPb->ioReqCount = kFWReadControlBufSize;
  793.  
  794.         err = CallFWXNode(pIOPb);
  795.         if (err != noErr) {
  796.             sprintf(debugStr, "Error in CallFWXNode, SetupReadQueue: %d", err);
  797.             FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  798.             break;
  799.         }
  800.     }
  801.     
  802.     if (err == noErr) {
  803.         // setup the data read parameter blocks
  804.         for (i=0; i < kFWReadDataBufs; i++) {
  805.             pIOPb = (IOParamPtr) NewPtrClear(sizeof(IOParam));
  806.             if (pIOPb != nil) {
  807.                 HoldMemory ((Ptr) pIOPb, sizeof(IOParam));
  808.             } else {
  809.                 FWDebugStr("\pOut of memory, SetupReadQueue");
  810.                 err = memFullErr;
  811.                 break;
  812.             }
  813.             
  814.             pIOPb->ioBuffer = NewPtr(kFWReadDataBufSize);
  815.             if (pIOPb->ioBuffer != nil) {
  816.                 HoldMemory (pIOPb->ioBuffer, kFWReadDataBufSize);
  817.             } else {
  818.                 UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  819.                 DisposePtr((Ptr) pIOPb);
  820.                 FWDebugStr("\pOut of memory, SetupReadQueue");
  821.                 err = memFullErr;
  822.                 break;
  823.             }
  824.             
  825.             // set up parameter block
  826.             pIOPb->ioNamePtr = (StringPtr) nodeID;
  827.             pIOPb->ioTrap = kFWXRead;
  828.             pIOPb->ioCompletion = (IOCompletionUPP) HandleFWReadComplete;
  829.             pIOPb->ioReqCount = kFWReadDataBufSize;
  830.             pIOPb->ioMisc = (Ptr) kForkData;
  831.         
  832.             err = CallFWXNode(pIOPb);
  833.             if (err != noErr) {
  834.                 sprintf(debugStr, "Error in CallFWXNode, SetupReadQueue: %d", err);
  835.                 FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  836.                 break;
  837.             }
  838.         }
  839.     }
  840.     return err;
  841. }
  842.  
  843. ////////////////////////////////////////////////////////////////////////////////
  844. //
  845. //    GetNodeIDFromEvent
  846. //
  847. //    Get the firewire file exchange node ID
  848. //    out of the device added or removed apple event
  849. //
  850. static OSErr GetNodeIDFromEvent(
  851.     AppleEvent            *pAEvent,
  852.     FWXNodeID            *nodeID)
  853. {
  854.     OSErr                err;
  855.     DescType            returnType;
  856.     Size                returnSize;
  857.  
  858.     err = AEGetParamPtr(pAEvent, kAEFWXNodeIDKey, kAEFWXNodeIDType, &returnType, 
  859.                         (Ptr) nodeID, sizeof(FWXNodeID), &returnSize);
  860.     return err;
  861. }
  862.  
  863. ////////////////////////////////////////////////////////////////////////////////
  864. //
  865. //    NewSenderWindow
  866. //
  867. //    Creates firwire sender window. Called when the first
  868. //    FireWire Exchange receive node is connected to the bus.
  869. //
  870.  
  871. static OSErr NewSenderWindow (void)
  872. {
  873.     WindowRef            pWin;
  874.     GrafPtr                curPort;
  875.     WindowDataPtr        pWinData;
  876.     MenuHandle            hMenu;
  877.     Rect                winRect;
  878.     OSErr                err = noErr;
  879.     
  880.     // open the window
  881.     pWin = GetNewCWindow(kWindowResourceID, nil, (WindowRef) -1);
  882.     
  883.     if (pWin == nil)
  884.         err = ResError();
  885.     else
  886.     {
  887.         // position and size window
  888.         err = GetWindowPos(&winRect);
  889.         if (err == noErr)
  890.         {
  891.             MoveWindow(pWin, winRect.left, winRect.top, false);
  892.             SizeWindow(pWin, winRect.right - winRect.left, winRect.bottom - winRect.top, false);
  893.         }
  894.         else
  895.             err = noErr;    // don't care if resource problem
  896.         
  897.         // Allocate window data structure
  898.         pWinData = (WindowDataPtr) NewPtrClear(sizeof(WindowData));
  899.         if (pWinData != nil)
  900.         {        
  901.             pWinData->numOpenNodes = 0;
  902.             pWinData->pOpenNodeList = nil;
  903.             pWinData->numRecvNodes = 0;
  904.             pWinData->pRecvNodeList = nil;
  905.             pWinData->hVScrollBar = GetNewControl(kVScrollBar, pWin);
  906.             if (pWinData->hVScrollBar == nil)
  907.                 err = ResError();
  908.             pWinData->hHScrollBar = GetNewControl(kHScrollBar, pWin);
  909.             if (pWinData->hHScrollBar == nil)
  910.                 err = ResError();
  911.             
  912.             SetWRefCon(pWin, (SInt32) pWinData);
  913.             if (err == noErr)
  914.                 AdjustScrollBars(pWin, true);
  915.         }
  916.         else
  917.         {
  918.             err = memFullErr;
  919.             DisposeWindow(pWin);
  920.         }
  921.     }
  922.     gpFWXAppData->pSenderWindow = pWin;
  923.     if (err == noErr)
  924.     {
  925.         GetPort(&curPort);
  926.         SetPort(pWin);
  927.         TextSize(9);
  928.         ClipRect(&qd.screenBits.bounds);
  929.         SetPort(curPort);
  930.     }
  931.     if (err == noErr)
  932.     {
  933.         if (gpFWXAppData->fwixPrefs & kIconView)
  934.         {
  935.             pWinData->windowView = kSmallIconView;
  936.             hMenu = GetMenuHandle(kViewMenuID);
  937.             SetItemMark(hMenu, kSmallIconMenuItem, checkMark);
  938.             SetItemMark(hMenu, kIconMenuItem, noMark);
  939.         }
  940.         else
  941.             pWinData->windowView = kLargeIconView;
  942.     }
  943.  
  944.     return err;
  945. }
  946.  
  947. //////////////////////////////////////////////////////////////////////////////
  948. //
  949. //    GetDisplayRect
  950. //
  951. //    Calculate the rectangle needed to display all of the sender window items.
  952. //
  953. static void GetDisplayRect (
  954.     Rect                    *r,
  955.     WindowPtr                pWin,
  956.     WindowDataPtr            pWinData)
  957. {
  958.     GrafPtr                    curPort;
  959.     Rect                    iconRect, textRect;
  960.     SInt16                    row, column;
  961.     SInt16                    index, count;
  962.  
  963.     GetPort(&curPort);
  964.     SetPort(pWin);
  965.     TextSize(9);
  966.  
  967.     if (pWinData->windowView == kLargeIconView)
  968.     {
  969.         row = pWinData->numRecvNodes % kLargeRowCount;
  970.         column = pWinData->numRecvNodes / kLargeRowCount;
  971.         if (column == 0)
  972.             count = row;
  973.         else
  974.             count = kLargeRowCount;
  975.             
  976.         // get smallest left value
  977.         for (index = 1; index <= count; index++)
  978.         {
  979.             GetNodeDragRect(pWin, index, &iconRect, &textRect);
  980.             if (textRect.left < iconRect.left)
  981.             {
  982.                 if (textRect.left < r->left)
  983.                     r->left = textRect.left;
  984.             }
  985.             else
  986.             {
  987.                 if (iconRect.left < r->left)
  988.                     r->left = iconRect.left;
  989.             }
  990.         }
  991.  
  992.         // get smallest top value
  993.         GetNodeDragRect(pWin, 1, &iconRect, &textRect);
  994.         if (iconRect.top < r->top)
  995.             r->top = iconRect.top;
  996.  
  997.         // get largest bottom value from lowest icon in row
  998.         GetNodeDragRect(pWin, count, &iconRect, &textRect);
  999.         if (textRect.bottom > r->bottom)
  1000.             r->bottom = textRect.bottom;
  1001.             
  1002.         // get largest right value by checking space needed for far right column
  1003.         for (index = ((column * kLargeRowCount) + 1); index <= pWinData->numRecvNodes; index++)
  1004.         {
  1005.             GetNodeDragRect(pWin, index, &iconRect, &textRect);
  1006.             if (textRect.right > iconRect.right)
  1007.             {
  1008.                 if (textRect.right > r->right)
  1009.                     r->right = textRect.right;
  1010.             }
  1011.             else
  1012.             {
  1013.                 if (iconRect.right > r->right)
  1014.                     r->right = iconRect.right;
  1015.             }
  1016.         }                
  1017.     }
  1018.     else
  1019.     {
  1020.         row = pWinData->numRecvNodes % kSmallRowCount;
  1021.         column = pWinData->numRecvNodes / kSmallRowCount;
  1022.         if (column == 0)
  1023.             count = row;
  1024.         else
  1025.             count = kSmallRowCount;
  1026.  
  1027.         // get smallest top left value
  1028.         GetNodeDragRect(pWin, 1, &iconRect, &textRect);
  1029.         if (iconRect.top < r->top)
  1030.             r->top = iconRect.top;
  1031.         if (iconRect.left < r->left)
  1032.             r->left = iconRect.left;
  1033.  
  1034.         // get largest bottom value from lowest icon in row
  1035.         GetNodeDragRect(pWin, count, &iconRect, &textRect);
  1036.         if (iconRect.bottom > r->bottom)
  1037.             r->bottom = iconRect.bottom;
  1038.             
  1039.         // get largest right value by checking space needed for far right column
  1040.         for (index = ((column * kSmallRowCount) + 1); index <= pWinData->numRecvNodes; index++)
  1041.         {
  1042.             GetNodeDragRect(pWin, index, &iconRect, &textRect);
  1043.             if (textRect.right > r->right)
  1044.                 r->right = textRect.right;
  1045.         }                
  1046.     }    
  1047.     SetPort(curPort);
  1048. }
  1049.  
  1050. //////////////////////////////////////////////////////////////////////////////
  1051. //
  1052. //    AdjustScrollBars
  1053. //
  1054. //    Adjust and size scroll bars
  1055. //
  1056. OSErr AdjustScrollBars (
  1057.     WindowPtr                pWin,
  1058.     Boolean                    adjustSizes)
  1059. {
  1060.     WindowDataPtr            pWinData;
  1061.     Rect                    viewRect,        // view able area in window
  1062.                             displayRect;    // area needed to display node list
  1063.     Rect                    ctlRect;
  1064.     SInt16                    displayH, displayV, viewH, viewV;
  1065.     SInt16                    ctlVal;
  1066.     OSErr                    err = noErr;
  1067.  
  1068.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  1069.     if (pWinData != nil)
  1070.     {
  1071.         // calculate view space available
  1072.         viewRect = pWin->portRect;
  1073.         viewRect.bottom -= kScrollBarAdjust;
  1074.         viewRect.right -= kScrollBarAdjust;
  1075.         displayRect = viewRect;
  1076.         
  1077.         GetDisplayRect (&displayRect, pWin, pWinData);
  1078.         displayH = displayRect.right - displayRect.left;
  1079.         viewH = viewRect.right - viewRect.left;
  1080.         
  1081.         if (displayH > viewH)
  1082.         {
  1083.             SetControlMaximum (pWinData->hHScrollBar, displayH - viewH);
  1084.             ctlVal = GetControlValue(pWinData->hHScrollBar);
  1085.             SetControlValue (pWinData->hHScrollBar, ctlVal + (viewRect.left - displayRect.left));
  1086.         }
  1087.         else
  1088.         {
  1089.             SetControlMaximum (pWinData->hHScrollBar, 0);
  1090.             SetControlValue (pWinData->hHScrollBar, 0);
  1091.         }
  1092.     
  1093.         displayV = displayRect.bottom - displayRect.top;
  1094.         viewV = viewRect.bottom - viewRect.top;
  1095.         if (displayV > viewV)
  1096.         {
  1097.             SetControlMaximum (pWinData->hVScrollBar, displayV - viewV);
  1098.             ctlVal = GetControlValue(pWinData->hVScrollBar);
  1099.             SetControlValue (pWinData->hVScrollBar, ctlVal + (viewRect.top - displayRect.top));
  1100.         }
  1101.         else
  1102.         {
  1103.             SetControlMaximum (pWinData->hVScrollBar, 0);
  1104.             SetControlValue (pWinData->hVScrollBar, 0);
  1105.         }
  1106.         
  1107.         if (adjustSizes)
  1108.         {
  1109.             // position and size vertical scroll bar
  1110.             ctlRect = pWin->portRect;
  1111.             MoveControl (pWinData->hVScrollBar,
  1112.                          ctlRect.right - kScrollBarAdjust,
  1113.                          -1);
  1114.             SizeControl (pWinData->hVScrollBar,
  1115.                          kScrollBarWidth,
  1116.                          (ctlRect .bottom - ctlRect.top) - (kScrollBarAdjust - kScrollBarTweek));
  1117.     
  1118.             // position and size horizontal scroll bar
  1119.             MoveControl (pWinData->hHScrollBar,
  1120.                          -1,
  1121.                          ctlRect.bottom - kScrollBarAdjust);
  1122.             SizeControl (pWinData->hHScrollBar,
  1123.                          (ctlRect.right - ctlRect.left) - (kScrollBarAdjust - kScrollBarTweek),
  1124.                          kScrollBarWidth);
  1125.         }
  1126.     }
  1127.     else
  1128.         err = resNotFound;
  1129.     return  err;
  1130. }
  1131.  
  1132. //////////////////////////////////////////////////////////////////////////////
  1133. //
  1134. //    InitRecvNode
  1135. //
  1136. //    Set up the node drag rectangles and node list.
  1137. //
  1138. OSErr InitRecvNode (
  1139.     FWXNodeID                nodeID,
  1140.     ConstStr255Param        nodeName)
  1141. {
  1142.     WindowPtr                pWin;
  1143.     WindowDataPtr            pWinData;
  1144.     RecvNodePtr                pRecvNode;
  1145.     RecvNodePtr                pTempRecvNode;
  1146.     SInt16                    rctTop, rctLeft, rctBottom, rctRight;
  1147.     SInt16                    row, column;    
  1148.     SInt16                    sLoc, sWidth;    
  1149.     OSErr                    err = noErr;
  1150.     
  1151.     pWin = gpFWXAppData->pSenderWindow;
  1152.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  1153.     if (pWinData == nil)
  1154.         return memFullErr;
  1155.         
  1156.     pRecvNode = (RecvNodePtr) NewPtrClear(sizeof(RecvNodeRecord));
  1157.     if (pRecvNode == nil)
  1158.         return memFullErr;
  1159.  
  1160.     pRecvNode->pReplyTimer = (MyTMTaskPtr) NewPtrClear(sizeof(MyTMTask));
  1161.     if (pRecvNode->pReplyTimer == nil)
  1162.         return memFullErr;
  1163.     else
  1164.     {
  1165.         pRecvNode->pReplyTimer->timerTask.tmAddr = NewTimerProc(HandleReplyTimeout);
  1166.         if (pRecvNode->pReplyTimer->timerTask.tmAddr == nil)
  1167.             return memFullErr;
  1168.             
  1169.         InsTime((QElemPtr) pRecvNode->pReplyTimer);
  1170.     }
  1171.  
  1172.     // init values
  1173.     pRecvNode->nodeID = nodeID;
  1174.     BlockMove(nodeName, pRecvNode->nodeName, nodeName[0] + 1);
  1175.     sWidth = StringWidth(pRecvNode->nodeName);
  1176.  
  1177.     // setup node drag rectangle
  1178.     if (pWinData->windowView == kLargeIconView)
  1179.     {
  1180.         row = pWinData->numRecvNodes % kLargeRowCount;
  1181.         column = pWinData->numRecvNodes / kLargeRowCount;
  1182.         rctLeft = kLargeHFill + (column * kLargeHSize);
  1183.         rctRight = rctLeft + kLargeIconFill;
  1184.         rctTop = kLargeVFill + (row * kLargeVSize);
  1185.         rctBottom = rctTop + kLargeIconFill;
  1186.  
  1187.         sLoc = rctLeft + ((rctRight - rctLeft) / 2);
  1188.         sLoc -= ((sWidth / 2) + 2);
  1189.         SetRect(&pRecvNode->recvNodeTextRect,
  1190.                 sLoc,
  1191.                 rctBottom,
  1192.                 sLoc + sWidth + 3,
  1193.                 rctBottom + 13); 
  1194.     }
  1195.     else
  1196.     {
  1197.         row = pWinData->numRecvNodes % kSmallRowCount;
  1198.         column = pWinData->numRecvNodes / kSmallRowCount;
  1199.         rctLeft = kSmallHFill + (column * kSmallHSize);
  1200.         rctRight = rctLeft + kSmallIconFill;
  1201.         rctTop = kSmallVFill + (row * kSmallVSize);
  1202.         rctBottom = rctTop + kSmallIconFill;
  1203.  
  1204.         SetRect(&pRecvNode->recvNodeTextRect,
  1205.                 rctRight + 2,
  1206.                 rctBottom - 15,
  1207.                 rctRight + sWidth + 5,
  1208.                 rctBottom - 2); 
  1209.     }    
  1210.     SetRect(&pRecvNode->recvNodeIconRect, rctLeft, rctTop, rctRight, rctBottom); 
  1211.     
  1212.     // increment node count after updating rectangles
  1213.     pWinData->numRecvNodes++;
  1214.     
  1215.     // add the node to the list, if the the first node, just point to it
  1216.     if (pWinData->numRecvNodes == 1)
  1217.         pWinData->pRecvNodeList = pRecvNode;
  1218.     else
  1219.     {
  1220.     // it is not the first node, traverse the list, add new node to the end
  1221.         pTempRecvNode = pWinData->pRecvNodeList;
  1222.         while (pTempRecvNode->pNextNode != nil)
  1223.             pTempRecvNode = pTempRecvNode->pNextNode;
  1224.         pTempRecvNode->pNextNode = pRecvNode;
  1225.         pRecvNode->pPreviousNode = pTempRecvNode;
  1226.     }
  1227.  
  1228.     AdjustScrollBars(pWin, false);
  1229.  
  1230.     return err;
  1231. }
  1232.  
  1233. //////////////////////////////////////////////////////////////////////////////
  1234. //
  1235. //    HandleReplyTimeout
  1236. //
  1237. //    For various communications with nodes, fwix posts a timer to wait for
  1238. //    a reply. If no reply is received this task is executed.
  1239. // 
  1240. //    JKL *** needs to have a variable timer to increase timeout period from
  1241. //    a few seconds up to a couple of minutes and eventually give up
  1242. // 
  1243. static pascal void HandleReplyTimeout (
  1244.     MyTMTaskPtr            pTMTask)
  1245. {
  1246.     gSendError = pTMTask->nodeID;
  1247. }
  1248.  
  1249. //////////////////////////////////////////////////////////////////////////////
  1250. //
  1251. //    HandleDeviceRemovedEvent
  1252. //
  1253. //    Called when a FWIX receiver node disconnects from the bus. If the node
  1254. //    had fwix open, clean up the node info and any sends. Otherwise close the node.
  1255. // 
  1256. //    JKL *** what if we are receiving data from this node? handle by HandleReceive timeout?
  1257. static pascal OSErr    HandleDeviceRemovedEvent (
  1258.     AppleEvent                *theAppleEvent,
  1259.     AppleEvent                *reply,
  1260.     long                    handlerRefcon)
  1261. {
  1262.     WindowDataPtr            pWinData;
  1263.     GrafPtr                    curPort;
  1264.     GrafPtr                    pWindowPort;
  1265.     RecvNodePtr                pTempRecvNode;
  1266.     OpenNodePtr                pTempOpenNode;
  1267.     FWXNodeID                targetNodeID;
  1268.     TxFSSpecPtr                pTxItem;
  1269.     OSErr                    err;
  1270.     Boolean                    foundNodeID;
  1271.  
  1272.     err = GetNodeIDFromEvent(theAppleEvent, &targetNodeID);
  1273.     if ((err == noErr) && (gSendingFile || gCheckingTransfer))
  1274.     {
  1275.         // if we are sending a file to the removed node,
  1276.         // dismiss the dialog, clean up send queue, and alert user
  1277.         if (targetNodeID == ((TxFSSpecPtr) gSendQHdr.qHead)->recvNode)
  1278.         {
  1279.             gCheckingTransfer = false;
  1280.             gSendingFile = false;
  1281.             gForkComplete = true;
  1282.             gForkWriteComplete = true;
  1283.             CleanupCopyDialog(FrontWindow());
  1284.             if (gSendingDataFork || gSendingResFork)
  1285.             {
  1286.                 gSendingDataFork = false;
  1287.                 gSendingResFork = false;
  1288.                 FSClose(gCurForkRefNum);
  1289.             }
  1290.     
  1291.             // dequeue and dispose of all file queue entries
  1292.             pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  1293.             while (pTxItem != nil)
  1294.             {
  1295.                 Dequeue((QElemPtr) pTxItem, &gSendQHdr);
  1296.                 DisposePtr((Ptr) pTxItem->pFSSpec);
  1297.                 DisposePtr((Ptr) pTxItem);
  1298.  
  1299.                 // get another queue item
  1300.                 pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  1301.             }
  1302.             
  1303.             GetNodeInfo(targetNodeID, &pTempRecvNode);
  1304.             ParamText(pTempRecvNode->nodeName, "\p", "\p", "\p");
  1305.             HandleCautionAlert(kNodeDisconnectAlertID);
  1306.         }
  1307.     }
  1308.     
  1309.     // Get the window data record
  1310.     pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  1311.     
  1312.     // Traverse the open node list to find the node record for the nodeID
  1313.     foundNodeID = false;
  1314.     pTempOpenNode = pWinData->pOpenNodeList;
  1315.     while ((pTempOpenNode != nil) && (!foundNodeID))
  1316.     {
  1317.         if (pTempOpenNode->nodeID == targetNodeID)
  1318.         {
  1319.             foundNodeID = true;
  1320.             break;
  1321.         }
  1322.         pTempOpenNode = pTempOpenNode->pNextNode;    
  1323.     }
  1324.  
  1325.     if (foundNodeID)
  1326.     {    
  1327.         // handle removing the node from the open node list
  1328.         if (pTempOpenNode->pNextNode != nil)
  1329.             pTempOpenNode->pNextNode->pPreviousNode = pTempOpenNode->pPreviousNode;
  1330.  
  1331.         if (pTempOpenNode->pPreviousNode != nil)
  1332.             pTempOpenNode->pPreviousNode->pNextNode = pTempOpenNode->pNextNode;
  1333.         else
  1334.             pWinData->pOpenNodeList = pTempOpenNode->pNextNode;
  1335.             
  1336.         DisposePtr((Ptr) pTempOpenNode);
  1337.         pWinData->numOpenNodes--;
  1338.         CloseFWXNode(targetNodeID);
  1339.     }
  1340.     
  1341.     // Traverse the receive node list to find the receive node record for the nodeID
  1342.     foundNodeID = false;
  1343.     pTempRecvNode = pWinData->pRecvNodeList;
  1344.     while ((pTempRecvNode != nil) && (!foundNodeID))
  1345.     {
  1346.         if (pTempRecvNode->nodeID == targetNodeID)
  1347.         {
  1348.             foundNodeID = true;
  1349.             break;
  1350.         }
  1351.         pTempRecvNode = pTempRecvNode->pNextNode;
  1352.     }
  1353.         
  1354.     if (foundNodeID)
  1355.     {    
  1356.         // remove the node from the list
  1357.         if (pTempRecvNode->pNextNode != nil)
  1358.             pTempRecvNode->pNextNode->pPreviousNode = pTempRecvNode->pPreviousNode;
  1359.             
  1360.         if (pTempRecvNode->pPreviousNode != nil)
  1361.             pTempRecvNode->pPreviousNode->pNextNode = pTempRecvNode->pNextNode;
  1362.         else
  1363.             pWinData->pRecvNodeList = pTempRecvNode->pNextNode;
  1364.         
  1365.         // JKL *** how about canceling timer?
  1366.         if (pTempRecvNode->pReplyTimer != nil)
  1367.         {
  1368.             if (pTempRecvNode->pReplyTimer->timerTask.tmAddr != nil)
  1369.                 DisposeRoutineDescriptor(pTempRecvNode->pReplyTimer->timerTask.tmAddr);
  1370.             DisposePtr((Ptr) pTempRecvNode->pReplyTimer);
  1371.         }
  1372.         DisposePtr((Ptr) pTempRecvNode);
  1373.         pWinData->numRecvNodes--;
  1374.         
  1375.         if (pWinData->numRecvNodes == 0)
  1376.         {
  1377.             HideWindow(gpFWXAppData->pSenderWindow);
  1378.             DisableItem(GetMenuHandle(kFileMenuID), kOpenMenuItem);
  1379.             DisableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  1380.             DisableItem(GetMenuHandle(kViewMenuID), 0);
  1381.             DrawMenuBar();
  1382.         }
  1383.         else
  1384.         {
  1385.             // Force an update
  1386.             GetPort(&curPort);
  1387.             pWindowPort = (GrafPtr) GetWindowPort(gpFWXAppData->pSenderWindow);
  1388.             AdjustNodeIcons(pWinData, &pWindowPort->portRect);
  1389.             AdjustScrollBars(gpFWXAppData->pSenderWindow, false);
  1390.             SetPortWindowPort(pWindowPort);
  1391.             InvalRect(&pWindowPort->portRect);
  1392.             SetPort(curPort);
  1393.         }
  1394.     }
  1395.     return err;
  1396. }
  1397.  
  1398. //////////////////////////////////////////////////////////////////////////////
  1399. //
  1400. //    AdjustNodeIcons
  1401. //
  1402. //    Adjust the placement of the node icons in the window. Traverse the list
  1403. //    of nodes setting the rectangle appropriately.
  1404. //
  1405.  
  1406. void AdjustNodeIcons (
  1407.     WindowDataPtr            pWinData,
  1408.     Rect                    *windRect)
  1409. {
  1410.     RecvNodePtr                pRecvNode;
  1411.     SInt16                    rctTop, rctLeft, rctBottom, rctRight;
  1412.     SInt16                    row, column;
  1413.     SInt16                    index;
  1414.     SInt16                    sWidth, sLoc;
  1415.     
  1416.     pRecvNode = pWinData->pRecvNodeList;
  1417.     for (index = 0; index < pWinData->numRecvNodes; index++)
  1418.     {
  1419.         if (pRecvNode == nil)
  1420.             FWDebugStr("\pNode List screwed up in AdjustNodeIcons");
  1421.             
  1422.         // setup drag rectangle
  1423.         sWidth = StringWidth(pRecvNode->nodeName);
  1424.         if (pWinData->windowView == kLargeIconView)
  1425.         {
  1426.             row = index % kLargeRowCount;
  1427.             column = index / kLargeRowCount;
  1428.             rctLeft = kLargeHFill + (column * kLargeHSize);
  1429.             rctRight = rctLeft + kLargeIconFill;
  1430.             rctTop = kLargeVFill + (row * kLargeVSize);
  1431.             rctBottom = rctTop + kLargeIconFill;
  1432.  
  1433.             sLoc = rctLeft + ((rctRight - rctLeft) / 2);
  1434.             sLoc -= ((sWidth / 2) + 2);
  1435.             SetRect(&pRecvNode->recvNodeTextRect,
  1436.                     sLoc,
  1437.                     rctBottom,
  1438.                     sLoc + sWidth + 3,
  1439.                     rctBottom + 13); 
  1440.         }
  1441.         else
  1442.         {
  1443.             row = index % kSmallRowCount;
  1444.             column = index / kSmallRowCount;
  1445.             rctLeft = kSmallHFill + (column * kSmallHSize);
  1446.             rctRight = rctLeft + kSmallIconFill;
  1447.             rctTop = kSmallVFill + (row * kSmallVSize);
  1448.             rctBottom = rctTop + kSmallIconFill;
  1449.  
  1450.             SetRect(&pRecvNode->recvNodeTextRect,
  1451.                     rctRight + 2,
  1452.                     rctBottom - 15,
  1453.                     rctRight + sWidth + 5,
  1454.                     rctBottom - 2); 
  1455.         }    
  1456.         SetRect(&pRecvNode->recvNodeIconRect, rctLeft, rctTop, rctRight, rctBottom);
  1457.         pRecvNode = (RecvNodePtr) pRecvNode->pNextNode;
  1458.     }
  1459. }
  1460.  
  1461.  
  1462. //////////////////////////////////////////////////////////////////////////////
  1463. //
  1464. //    HandleGetNodeListEvent
  1465. //
  1466. //    Handle the get node list applescript command
  1467. //
  1468.  
  1469. static pascal OSErr HandleGetNodeListEvent (
  1470.     AppleEvent                *pAppleEvent,
  1471.     AppleEvent                *pReplyEvent,
  1472.     SInt32                    refCon)
  1473. {
  1474.     WindowDataPtr    pWinData;
  1475.     RecvNodePtr        pNodeInfo;
  1476.     AEDescList        nodeList;
  1477.        OSErr            err = noErr;
  1478.  
  1479.     err = AECreateList(nil, 0, false, &nodeList);
  1480.     if (err == noErr) {
  1481.     
  1482.         pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  1483.         if (pWinData != nil)
  1484.         {
  1485.             pNodeInfo = pWinData->pRecvNodeList;
  1486.             while ((pNodeInfo != nil) && (!err))
  1487.             {
  1488.                 err = AEPutPtr(&nodeList, 0, typeChar, pNodeInfo->nodeName + 1, pNodeInfo->nodeName[0]);
  1489.                 pNodeInfo = pNodeInfo->pNextNode;
  1490.             }
  1491.             if (err == noErr)
  1492.                 err = AEPutKeyDesc(pReplyEvent, keyDirectObject, &nodeList);
  1493.         }
  1494.     }
  1495.     
  1496.     return  err;
  1497. }
  1498.  
  1499. //////////////////////////////////////////////////////////////////////////////
  1500. //
  1501. //    HandleSendItemsEvent
  1502. //
  1503. //    Handle the send applescript command
  1504. //
  1505. static pascal OSErr HandleSendItemsEvent (
  1506.     AppleEvent                *pAppleEvent,
  1507.     AppleEvent                *pReplyEvent,
  1508.     SInt32                    refCon)
  1509. {
  1510.     FWXNodeID                *pNodeIDList = nil;
  1511.     FSSpecPtr                pFileSpecList = nil;
  1512.     AESendRecPtr            pAESendElem;
  1513.     UInt16                    numFSItems;
  1514.     UInt16                    numNodes;
  1515.     UInt16                    index;
  1516.     OSErr                    err;
  1517.     
  1518.     // get items to be sent from event
  1519.     err = GetFSItemsFromEvent(&pFileSpecList, pAppleEvent, &numFSItems);
  1520.  
  1521.     // get the list of receive targets from event
  1522.     if (err == noErr)
  1523.         err = GetReceiveNodesFromEvent(&pNodeIDList, pAppleEvent, &numNodes);
  1524.         
  1525.     if (err == noErr)
  1526.     {
  1527.         for (index = 0; index < numNodes; index++)
  1528.         {
  1529.             pAESendElem = (AESendRecPtr) NewPtr(sizeof(AESendRec));
  1530.             if (pAESendElem == nil)
  1531.             {
  1532.                 err = memFullErr;
  1533.                 break;
  1534.             }
  1535.             else
  1536.             {
  1537.                 pAESendElem->pSendItemsList = (FSSpecPtr) NewPtr(sizeof(FSSpec) * numFSItems);
  1538.                 if (pAESendElem->pSendItemsList != nil)
  1539.                 {
  1540.                     BlockMove(pFileSpecList, pAESendElem->pSendItemsList, sizeof(FSSpec) * numFSItems);
  1541.                     pAESendElem->recvNode = pNodeIDList[index];
  1542.                     pAESendElem->numSendItems = numFSItems;
  1543.                     Enqueue((QElemPtr) pAESendElem, &gAESendQHdr);
  1544.                 }
  1545.                 else
  1546.                 {
  1547.                     err = memFullErr;
  1548.                     break;
  1549.                 }
  1550.             }
  1551.         }
  1552.     }
  1553.     
  1554.     if (pNodeIDList != nil)
  1555.         DisposePtr((Ptr) pNodeIDList);
  1556.     if (pFileSpecList != nil)
  1557.         DisposePtr((Ptr) pFileSpecList);
  1558.         
  1559.     if (!(gSendingFile || gCheckingTransfer))
  1560.     {
  1561.         pAESendElem = (AESendRecPtr) gAESendQHdr.qHead;
  1562.         if (pAESendElem != nil)
  1563.         {
  1564.             Dequeue((QElemPtr) pAESendElem, &gAESendQHdr);
  1565.             SendFSSpecListToSelf(pAESendElem->recvNode, pAESendElem->pSendItemsList, pAESendElem->numSendItems);
  1566.             DisposePtr((Ptr) pAESendElem->pSendItemsList);
  1567.             DisposePtr((Ptr) pAESendElem);
  1568.         }
  1569.     }
  1570.     
  1571.     err = AEPutKeyPtr(pReplyEvent, keyDirectObject, typeShortInteger, &err, sizeof(OSErr));
  1572.     return err;
  1573. }
  1574.  
  1575. //////////////////////////////////////////////////////////////////////////////
  1576. //
  1577. //    GetReceiveNodesFromEvent
  1578. //
  1579. //    Get the target nodes for the transfer out of the event
  1580. //
  1581. static OSErr GetReceiveNodesFromEvent (
  1582.     FWXNodeID                **pReceiveNodeIDList,
  1583.     AppleEvent                *pAppleEvent,
  1584.     UInt16                    *numNodes)
  1585. {    
  1586.     Ptr                        p = nil;
  1587.     AEDescList                descriptorList;
  1588.     SInt32                    itemCount;
  1589.     AEKeyword                keywd;
  1590.     DescType                returnedType;
  1591.     Size                    actualSize;
  1592.     UInt16                    i;
  1593.     OSErr                    err;
  1594.     
  1595.     err = AEGetParamDesc(pAppleEvent, kAEFWXNodeKeyword, typeAEList, &descriptorList);
  1596.     if (err == noErr)
  1597.     {
  1598.         err = AECountItems(&descriptorList, &itemCount);
  1599.         if (err == noErr)
  1600.         {
  1601.             *numNodes = itemCount;
  1602.             *pReceiveNodeIDList = (FWXNodeID *) NewPtr(sizeof(FWXNodeID) * itemCount);
  1603.             if (*pReceiveNodeIDList == nil)
  1604.                 err = memFullErr;
  1605.         }
  1606.     
  1607.         if (err == noErr)
  1608.         {
  1609.             for (i = 1; i <= itemCount; i++)
  1610.             {
  1611.                 err = AEGetNthPtr(&descriptorList, i, typeChar, &keywd, &returnedType,
  1612.                                     p, 0, &actualSize);
  1613.                 if (err == noErr)
  1614.                 {
  1615.                     p = NewPtr(actualSize + 1);
  1616.                     if (p == nil)
  1617.                     {
  1618.                         err = memFullErr;
  1619.                         break;
  1620.                     }
  1621.                     
  1622.                     err = AEGetNthPtr(&descriptorList, i, typeChar, &keywd, &returnedType,
  1623.                                     p + 1, actualSize, &actualSize);
  1624.                     p[0] = actualSize;
  1625.                     err = GetNodeIDFromName(&((*pReceiveNodeIDList)[i-1]), (ConstStr255Param) p);
  1626.                     DisposePtr(p);
  1627.                     if (err != noErr)
  1628.                         break;
  1629.                 }
  1630.             }
  1631.         }
  1632.         AEDisposeDesc(&descriptorList);
  1633.     }
  1634.     return err;
  1635. }
  1636.  
  1637. //////////////////////////////////////////////////////////////////////////////
  1638. //
  1639. //    GetNodeIDFromName
  1640. //
  1641. //    Get the node id from the node name.
  1642. //
  1643. static OSErr GetNodeIDFromName (
  1644.     FWXNodeID                *nodeID,
  1645.     ConstStr255Param        nodeName)
  1646. {
  1647.     WindowDataPtr            pWinData;
  1648.     RecvNodePtr                pRecvNode;
  1649.     OSErr                    err = noErr;
  1650.     
  1651.     pWinData = (WindowDataPtr) GetWRefCon(gpFWXAppData->pSenderWindow);
  1652.     if (pWinData == nil)
  1653.         return memFullErr;
  1654.         
  1655.     *nodeID = kInvalidFWXNodeID;
  1656.     pRecvNode = pWinData->pRecvNodeList;
  1657.     while (pRecvNode != nil)
  1658.     {
  1659.         if (EqualString(nodeName, pRecvNode->nodeName, false, false))
  1660.             break;
  1661.         pRecvNode = pRecvNode->pNextNode;
  1662.     }
  1663.  
  1664.     if (pRecvNode == nil)
  1665.         err = qErr;        // nodeName not found
  1666.     else
  1667.         *nodeID = pRecvNode->nodeID;
  1668.  
  1669.     return err;
  1670. }
  1671.  
  1672.  
  1673. //////////////////////////////////////////////////////////////////////////////
  1674. //
  1675. //    GetFSItemsFromEvent
  1676. //
  1677. //    Get the list of items to be sent out of the appleevent.
  1678. //
  1679. static OSErr GetFSItemsFromEvent (
  1680.     FSSpecPtr                *pSendItems,
  1681.     AppleEvent                *pEvent,
  1682.     UInt16                    *numItems)
  1683. {    
  1684.     Ptr                        p;
  1685.     FSSpecPtr                pFileList;
  1686.     AEDescList                descriptorList;
  1687.     AEKeyword                keywd;
  1688.     DescType                returnedType;
  1689.     Size                    actualSize;
  1690.     SInt32                    itemCount;
  1691.     SInt32                    i;
  1692.     OSErr                    err;
  1693.  
  1694.     err = AEGetParamDesc(pEvent, keyDirectObject, typeAEList, &descriptorList);
  1695.     if (err == noErr)
  1696.     {
  1697.         err = AECountItems(&descriptorList, &itemCount);
  1698.         pFileList = (FSSpecPtr) NewPtr(sizeof(FSSpec) * itemCount);
  1699.         if (pFileList == nil)
  1700.             err = memFullErr;
  1701.         
  1702.         if (err == noErr)
  1703.         {
  1704.             for (i = 1; i <= itemCount; i++)
  1705.             {
  1706.                 err = AEGetNthPtr(&descriptorList, i, typeFSS, &keywd, &returnedType,
  1707.                                     &pFileList[i-1], sizeof(FSSpec), &actualSize);
  1708.                 if (err == errAECoercionFail)
  1709.                 {
  1710.                     // try getting the data out as string and rolling our own fsspec
  1711.                     err = AEGetNthPtr(&descriptorList, i, typeChar, &keywd, &returnedType,
  1712.                                         p, 0, &actualSize);
  1713.                     if (err == noErr)
  1714.                     {
  1715.                         p = NewPtr(actualSize + 1);
  1716.                         if (p != nil)
  1717.                         {
  1718.                             err = AEGetNthPtr(&descriptorList, i, typeChar, &keywd, &returnedType,
  1719.                                                 p + 1, actualSize, &actualSize);
  1720.                             if (err == noErr)
  1721.                             {
  1722.                                 p[0] = actualSize;
  1723.                                 err = FSMakeFSSpec(0, 0, (ConstStr255Param) p, &pFileList[i-1]);
  1724.                             }
  1725.                             DisposePtr(p);
  1726.                         }
  1727.                         else
  1728.                         {
  1729.                             err = errAECoercionFail;
  1730.                             break;
  1731.                         }
  1732.                     }
  1733.                 } 
  1734.             }
  1735.         }
  1736.         AEDisposeDesc(&descriptorList);
  1737.         *numItems = itemCount;
  1738.         *pSendItems = pFileList;
  1739.     }
  1740.     return err;
  1741. }
  1742.  
  1743.  
  1744. //////////////////////////////////////////////////////////////////////////////
  1745. //
  1746. //    HandleOpenApplicationEvent
  1747. //
  1748. //    Do nothing for now
  1749. //
  1750.  
  1751. static pascal OSErr HandleOpenApplicationEvent (
  1752.     AppleEvent                *pAppleEvent,
  1753.     AppleEvent                *pReplyEvent,
  1754.     SInt32                    refCon)
  1755. {
  1756.     return noErr;
  1757. }
  1758.  
  1759. //////////////////////////////////////////////////////////////////////////////
  1760. //
  1761. //    HandleOpenDocumentsEvent
  1762. //
  1763. //    Do nothing for now, eventually send a list of items
  1764. //
  1765.  
  1766. static pascal OSErr HandleOpenDocumentsEvent (
  1767.     AppleEvent                *pAppleEvent,
  1768.     AppleEvent                *pReplyEvent,
  1769.     SInt32                    refCon)
  1770. {
  1771.     return noErr;
  1772. }
  1773.  
  1774. //////////////////////////////////////////////////////////////////////////////
  1775. //
  1776. //    HandleQuitApplicationEvent
  1777. //
  1778. //    quit the app
  1779. //
  1780.  
  1781. static pascal OSErr HandleQuitApplicationEvent (
  1782.     AppleEvent                *pAppleEvent,
  1783.     AppleEvent                *pReplyEvent,
  1784.     SInt32                    refCon)
  1785. {
  1786.  
  1787.     HandleQuit();     // set the quit flag (doesn't immediately quit)
  1788.     return noErr;
  1789. }
  1790.  
  1791.  
  1792. //////////////////////////////////////////////////////////////////////////////
  1793. //
  1794. // InstallAppleEventHandlers
  1795. //
  1796. // Setup handlers for standard open app, open documents, quit app
  1797. // Also handler for when a user drops files on a FireWire Exchange node.
  1798. //
  1799.  
  1800. static OSErr InstallAppleEventHandlers (void)
  1801. {
  1802.     OSErr err = noErr;
  1803.     
  1804.     // Create open application event handler.
  1805.     gpFWXAppData->openApplicationEventHandler =
  1806.         NewAEEventHandlerProc (HandleOpenApplicationEvent);
  1807.     if (gpFWXAppData->openApplicationEventHandler == nil)
  1808.         err = memFullErr;
  1809.  
  1810.     // Install handler.
  1811.     if (err == noErr) {
  1812.         err = AEInstallEventHandler
  1813.                 (kCoreEventClass,
  1814.                  kAEOpenApplication,
  1815.                  gpFWXAppData->openApplicationEventHandler,
  1816.                  (SInt32) gpFWXAppData,
  1817.                  false);
  1818.         if (err == noErr) {
  1819.             gpFWXAppData->openApplicationEventHandlerInstalled =
  1820.                 true;
  1821.         }
  1822.     }
  1823.  
  1824.     if (err == noErr) {
  1825.         // Create open documents event handler.
  1826.         gpFWXAppData->openDocumentsEventHandler =
  1827.             NewAEEventHandlerProc (HandleOpenDocumentsEvent);
  1828.         if (gpFWXAppData->openDocumentsEventHandler == nil)
  1829.             err = memFullErr;
  1830.     
  1831.         // Install handler.
  1832.         if (err == noErr) {
  1833.             err = AEInstallEventHandler
  1834.                     (kCoreEventClass,
  1835.                      kAEOpenDocuments,
  1836.                      gpFWXAppData->openDocumentsEventHandler,
  1837.                      (SInt32) gpFWXAppData,
  1838.                      false);
  1839.             if (err == noErr) {
  1840.                 gpFWXAppData->openDocumentsEventHandlerInstalled =
  1841.                     true;
  1842.             }
  1843.         }
  1844.     }
  1845.  
  1846.     if (err == noErr) {
  1847.         // Create quit application event handler.
  1848.         gpFWXAppData->quitApplicationEventHandler =
  1849.             NewAEEventHandlerProc (HandleQuitApplicationEvent);
  1850.         if (gpFWXAppData->quitApplicationEventHandler == nil)
  1851.             err = memFullErr;
  1852.     
  1853.         // Install handler.
  1854.         if (err == noErr) {
  1855.             err = AEInstallEventHandler
  1856.                     (kCoreEventClass,
  1857.                      kAEQuitApplication,
  1858.                      gpFWXAppData->quitApplicationEventHandler,
  1859.                      (SInt32) gpFWXAppData,
  1860.                      false);
  1861.             if (err == noErr) {
  1862.                 gpFWXAppData->quitApplicationEventHandlerInstalled =
  1863.                     true;
  1864.             }
  1865.         }
  1866.     }
  1867.  
  1868.     if (err == noErr) {
  1869.         // Create fsspec list handler.
  1870.         gpFWXAppData->fileSpecListHandler =
  1871.             NewAEEventHandlerProc (HandleAEFileSpecList);
  1872.         if (gpFWXAppData->fileSpecListHandler == nil)
  1873.             err = memFullErr;
  1874.     
  1875.         // Install handler.
  1876.         if (err == noErr) {
  1877.             err = AEInstallEventHandler
  1878.                     (kAEFWXEventClass,
  1879.                      kAEFileSpecList,
  1880.                      gpFWXAppData->fileSpecListHandler,
  1881.                      (SInt32) gpFWXAppData,
  1882.                      false);
  1883.             if (err == noErr) {
  1884.                 gpFWXAppData->fileSpecListHandlerInstalled =
  1885.                     true;
  1886.             }
  1887.         }
  1888.     }
  1889.     
  1890.     // Create device added event handler.
  1891.     if (err == noErr) {
  1892.         gpFWXAppData->deviceAddedEventHandler =
  1893.             NewAEEventHandlerProc (HandleDeviceAddedEvent);
  1894.         if (gpFWXAppData->deviceAddedEventHandler == nil)
  1895.             err = memFullErr;
  1896.     }
  1897.  
  1898.     // Install handler.
  1899.     if (err == noErr) {
  1900.         err = AEInstallEventHandler
  1901.                 (kAEFWXEventClass,
  1902.                  kAEFWXDeviceAdded,
  1903.                  gpFWXAppData->deviceAddedEventHandler,
  1904.                  (SInt32) gpFWXAppData,
  1905.                  false);
  1906.         if (err == noErr) {
  1907.             gpFWXAppData->deviceAddedEventHandlerInstalled =
  1908.                 true;
  1909.         }
  1910.     }
  1911.  
  1912.     // Create device removed event handler.
  1913.     if (err == noErr)
  1914.     {
  1915.         gpFWXAppData->deviceRemovedEventHandler =
  1916.             NewAEEventHandlerProc (HandleDeviceRemovedEvent);
  1917.         if (gpFWXAppData->deviceRemovedEventHandler == nil)
  1918.             err = memFullErr;
  1919.     }
  1920.  
  1921.     // Install handler.
  1922.     if (err == noErr)
  1923.     {
  1924.         err = AEInstallEventHandler
  1925.                 (kAEFWXEventClass,
  1926.                  kAEFWXDeviceRemoved,
  1927.                  gpFWXAppData->deviceRemovedEventHandler,
  1928.                  (SInt32) gpFWXAppData,
  1929.                  false);
  1930.         if (err == noErr)
  1931.         {
  1932.             gpFWXAppData->deviceRemovedEventHandlerInstalled =
  1933.                 true;
  1934.         }
  1935.     }
  1936.  
  1937.     // Create device send items event handler.
  1938.     if (err == noErr)
  1939.     {
  1940.         gpFWXAppData->sendItemsEventHandler =
  1941.             NewAEEventHandlerProc (HandleSendItemsEvent);
  1942.         if (gpFWXAppData->sendItemsEventHandler == nil)
  1943.             err = memFullErr;
  1944.     }
  1945.  
  1946.     // Install handler.
  1947.     if (err == noErr)
  1948.     {
  1949.         err = AEInstallEventHandler
  1950.                 (kAEFWXEventClass,
  1951.                  kAEFWXSendEventID,
  1952.                  gpFWXAppData->sendItemsEventHandler,
  1953.                  (SInt32) gpFWXAppData,
  1954.                  false);
  1955.         if (err == noErr)
  1956.         {
  1957.             gpFWXAppData->sendItemsEventHandlerInstalled =
  1958.                 true;
  1959.         }
  1960.     }
  1961.  
  1962.     // Create get node list event handler.
  1963.     if (err == noErr)
  1964.     {
  1965.         gpFWXAppData->getNodeListEventHandler =
  1966.             NewAEEventHandlerProc (HandleGetNodeListEvent);
  1967.         if (gpFWXAppData->getNodeListEventHandler == nil)
  1968.             err = memFullErr;
  1969.     }
  1970.  
  1971.     // Install handler.
  1972.     if (err == noErr)
  1973.     {
  1974.         err = AEInstallEventHandler
  1975.                 (kAEFWXEventClass,
  1976.                  kAEFWXNodeListID,
  1977.                  gpFWXAppData->getNodeListEventHandler,
  1978.                  (SInt32) gpFWXAppData,
  1979.                  false);
  1980.         if (err == noErr)
  1981.         {
  1982.             gpFWXAppData->getNodeListEventHandlerInstalled =
  1983.                 true;
  1984.         }
  1985.     }
  1986.     return err;
  1987. }
  1988.  
  1989.  
  1990. //////////////////////////////////////////////////////////////////////////////
  1991. //
  1992. // InstallCompletionRoutineProcs
  1993. //
  1994. // Setup handlers for our file read/write async completion procs
  1995. //    and FireWire read/write async completion procs
  1996. //
  1997.  
  1998. enum {
  1999.     uppIOCompletionProcWorkaroundInfo =
  2000.         kRegisterBased |
  2001.         RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) |
  2002.         REGISTER_RESULT_LOCATION(kRegisterD0) |
  2003.         REGISTER_ROUTINE_PARAMETER(1, kRegisterA0, SIZE_CODE(sizeof(ParmBlkPtr)))
  2004. };
  2005.  
  2006. #define NewIOCompletionProcWorkaround(userRoutine)        \
  2007.         (IOCompletionUPP) NewRoutineDescriptor((ProcPtr)(userRoutine),    \
  2008.                                                uppIOCompletionProcWorkaroundInfo,    \
  2009.                                                GetCurrentArchitecture())
  2010.  
  2011. static OSErr InstallCompletionRoutineProcs (void)
  2012. {
  2013.     OSErr err = noErr;
  2014.     
  2015.     gpFWXAppData->fileReadCompletionHandler =
  2016.         NewIOCompletionProcWorkaround(HandleFileReadComplete);
  2017.  
  2018.     if (gpFWXAppData->fileReadCompletionHandler == nil)
  2019.         err = memFullErr;
  2020.     else
  2021.         HoldMemory(gpFWXAppData->fileReadCompletionHandler, 32*1024);    // JKL some large amount
  2022.  
  2023.     if (err == noErr) {
  2024.         gpFWXAppData->fileWriteCompletionHandler =
  2025.             NewIOCompletionProcWorkaround(HandleFileWriteComplete);
  2026.     
  2027.         if (gpFWXAppData->fileWriteCompletionHandler == nil)
  2028.             err = memFullErr;
  2029.         else
  2030.             HoldMemory(gpFWXAppData->fileWriteCompletionHandler, 32*1024);    // JKL some large amount
  2031.     
  2032.         // while here go ahead and hold some other interrupt level stuff
  2033.         HoldMemory(HandleFWWriteComplete, 32*1024);
  2034.         HoldMemory(HandleFWReadComplete, 32*1024);
  2035.         HoldMemory(HandleFWControlComplete, 32*1024);
  2036.         HoldMemory(FWIXDequeue, 32*1024);
  2037.         HoldMemory(SetupFileReadPB, 32*1024);
  2038.         HoldMemory(&gFileReadQHdr, 32*1024);
  2039.         HoldMemory(&gFWControlQHdr, 32*1024);
  2040.         HoldMemory(&gReceiveQHdr, 32*1024);
  2041.     }
  2042.  
  2043.     return err;
  2044.  
  2045. }
  2046.  
  2047. ////////////////////////////////////////////////////////////////////////////////
  2048. //
  2049. // DrawWindow
  2050. //
  2051. //    Draws the space areas in the window
  2052. //
  2053. static void DrawWindow (
  2054.     WindowPtr            pWin)
  2055. {
  2056.     Handle                hIconSuite;
  2057.     RgnHandle            hOldClip;
  2058.     WindowDataPtr        pWinData;
  2059.     StringPtr            pString;
  2060.     Rect                iconRect, textRect;
  2061.     Rect                drawRect;
  2062.     SInt16                nodeIndex;
  2063.     OSErr                err;
  2064.     
  2065.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2066.     if (pWinData != nil)
  2067.     {
  2068.         GetClip(hOldClip = NewRgn());
  2069.         EraseRect(&pWin->portRect);
  2070.         DrawControls(pWin);
  2071.         DrawGrowIcon(pWin);
  2072.     
  2073.         SetOrigin (GetControlValue(pWinData->hHScrollBar),
  2074.                    GetControlValue(pWinData->hVScrollBar));
  2075.         drawRect = pWin->portRect;
  2076.         drawRect.bottom -= kScrollBarAdjust;
  2077.         drawRect.right -= kScrollBarAdjust;
  2078.         ClipRect(&drawRect);
  2079.         
  2080.         err = GetIconSuite(&hIconSuite, kDropIconSuiteID, svAllAvailableData);
  2081.         for (nodeIndex = 1; nodeIndex <= pWinData->numRecvNodes; nodeIndex ++)
  2082.         {
  2083.             GetNodeDragRect(pWin, nodeIndex, &iconRect, &textRect);
  2084.             GetNodeName(pWin, nodeIndex, &pString);
  2085.             PlotIconSuite(&iconRect, atNone, ttNone, hIconSuite);
  2086.             InsetRect(&textRect, 1, 0);
  2087.             TETextBox(pString + 1, pString[0], &textRect, teJustLeft);
  2088.         }
  2089.         DisposeIconSuite(hIconSuite, false);
  2090.         SetOrigin(0, 0);
  2091.         SetClip(hOldClip);
  2092.         DisposeRgn(hOldClip);
  2093.     }
  2094. }
  2095.  
  2096. ////////////////////////////////////////////////////////////////////////////////
  2097. //
  2098. //    CreateMenus
  2099. //
  2100. //    Make our menu bar. We only do about, open, and quit.
  2101. //
  2102.  
  2103. static OSErr CreateMenus()
  2104. {
  2105.     OSErr        err = noErr;
  2106.     Handle        hMenuBarResource;
  2107.     
  2108.     hMenuBarResource = GetNewMBar (kMenuBarResourceID);
  2109.     if (hMenuBarResource != nil)
  2110.     {
  2111.         SetMenuBar (hMenuBarResource);
  2112.         DisposeHandle (hMenuBarResource);
  2113.         AppendResMenu (GetMenuHandle (kAppleMenuID), 'DRVR');
  2114.         DrawMenuBar ();
  2115.     } else
  2116.         err = resNotFound;
  2117.  
  2118.     return err;
  2119. }
  2120.  
  2121.  
  2122. ////////////////////////////////////////////////////////////////////////////////
  2123. //
  2124. //    HandleCloseWindow
  2125. //
  2126. //    Disposes of a window and its refcon memory.
  2127. //
  2128.  
  2129. static void HandleCloseWindow (
  2130.     WindowPtr        pWin)
  2131. {
  2132.     WindowDataPtr    pWinData;
  2133.     OpenNodePtr        pTempOpenNode;
  2134.     RecvNodePtr        pTempRecvNode;
  2135.     
  2136.     if (pWin != nil) {
  2137.         pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2138.         if (pWinData != nil) {
  2139.         
  2140.             // dispose of the receive node records
  2141.             pTempRecvNode = pWinData->pRecvNodeList;
  2142.             while (pTempRecvNode != nil)
  2143.             {
  2144.                 if (pTempRecvNode->pReplyTimer != nil)
  2145.                 {
  2146.                     if (pTempRecvNode->pReplyTimer->timerTask.tmAddr != nil)
  2147.                         DisposeRoutineDescriptor(pTempRecvNode->pReplyTimer->timerTask.tmAddr);
  2148.                     DisposePtr((Ptr) pTempRecvNode->pReplyTimer);
  2149.                 }
  2150.                     
  2151.                 pTempRecvNode = (RecvNodePtr) pTempRecvNode->pNextNode;
  2152.                 DisposePtr((Ptr) pWinData->pRecvNodeList);
  2153.                 pWinData->pRecvNodeList = pTempRecvNode;
  2154.             }
  2155.             
  2156.             // dispose of the open node records
  2157.             pTempOpenNode = pWinData->pOpenNodeList;
  2158.             while (pTempOpenNode != nil)
  2159.             {
  2160.                 CloseFWXNode(pTempOpenNode->nodeID);
  2161.                 
  2162.                 pTempOpenNode = (OpenNodePtr) pTempOpenNode->pNextNode;
  2163.                 DisposePtr((Ptr) pWinData->pOpenNodeList);
  2164.                 pWinData->pOpenNodeList = pTempOpenNode;
  2165.             }
  2166.             
  2167.             DisposePtr((Ptr) pWinData);
  2168.             DisposeWindow(pWin);
  2169.         }
  2170.     }
  2171. }
  2172.  
  2173. //////////////////////////////////////////////////////////////////////////////
  2174. //
  2175. //    HandleQuit
  2176. //
  2177. //    Quit the app
  2178. //
  2179.  
  2180. static void HandleQuit (void)
  2181. {
  2182.     SInt16            itemHit;
  2183.     
  2184.     if (gSendingFile || gCheckingTransfer) {
  2185.         // JKL *** does ok button work right? Complete and then quit
  2186.         // is background processing correct?
  2187.         itemHit = HandleCautionAlert(kCantQuitAlertID);
  2188.         if (itemHit == kCancelButton) {        // the abort and quit button
  2189.             StopTransfer(nil);
  2190.             gpFWXAppData->quitFlag = true;
  2191.         }
  2192.     } else {
  2193.         gpFWXAppData->quitFlag = true;
  2194.     }
  2195.     
  2196.     if (gpFWXAppData->quitFlag) {
  2197.         SendFWXQuit();
  2198.         if (gpFWXAppData->pNotifyRec->nmRefCon == kNotificationPosted)
  2199.             NMRemove(gpFWXAppData->pNotifyRec);
  2200.             
  2201.         if (gpFWXAppData->pSenderWindow != nil)
  2202.             HandleCloseWindow(gpFWXAppData->pSenderWindow);
  2203.         RemoveDragHandlers();
  2204.     }
  2205.  
  2206. }
  2207.  
  2208.  
  2209. //////////////////////////////////////////////////////////////////////////////
  2210. //
  2211. //    HandleMenuCommand
  2212. //
  2213. //    handle repsonses to user menu selections
  2214. //
  2215.  
  2216. static void HandleMenuCommand(
  2217.     SInt32                    menuCommand)
  2218. {
  2219.     VersRecHndl                h;
  2220.     WindowPtr                pWin;
  2221.     UInt8                    *vers;
  2222.     SInt16                    menuID;
  2223.     SInt16                    menuItem;
  2224.     Str255                    deskAccessoryName;
  2225.     
  2226.     menuID = menuCommand >> 16;
  2227.     menuItem = menuCommand & 0xFFFF;
  2228.  
  2229.     switch (menuID)
  2230.     {
  2231.         case kAppleMenuID:
  2232.             if (menuItem == kAboutMenuItem)
  2233.             {
  2234.                 h = (VersRecHndl) Get1Resource('vers', 1);
  2235.                 vers = (**h).shortVersion;
  2236.                 vers += (vers[0] + 1);
  2237.                 ParamText(vers, "\p", "\p", "\p");
  2238.                 HandleAlert(kAboutAlertResourceID);
  2239.             }
  2240.             else
  2241.             {
  2242.                 GetMenuItemText(GetMenuHandle(kAppleMenuID), menuItem, deskAccessoryName);
  2243.                 OpenDeskAcc(deskAccessoryName);
  2244.             }
  2245.             break;
  2246.  
  2247.         case kFileMenuID:
  2248.             switch (menuItem)
  2249.             {
  2250.                 case kOpenMenuItem:
  2251.                     pWin = gpFWXAppData->pSenderWindow;
  2252.                     ShowWindow(pWin);
  2253.                     EnableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  2254.                     DisableItem(GetMenuHandle(kFileMenuID), kOpenMenuItem);
  2255.                     EnableItem(GetMenuHandle(kViewMenuID), 0);
  2256.                     DrawMenuBar();
  2257.                     break;
  2258.                 case kCloseMenuItem:
  2259.                     pWin = gpFWXAppData->pSenderWindow;
  2260.                     HideWindow(pWin);
  2261.                     EnableItem(GetMenuHandle(kFileMenuID), kOpenMenuItem);
  2262.                     DisableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  2263.                     DisableItem(GetMenuHandle(kViewMenuID), 0);
  2264.                     DrawMenuBar();
  2265.                     break;
  2266.                 case kOpenDropMenuItem:
  2267.                     OpenDropFolder();
  2268.                     break;
  2269.                 case kQuitMenuItem:
  2270.                     HandleQuit();
  2271.                     break;
  2272.             }
  2273.             break;
  2274.         case kEditMenuID:
  2275.             switch (menuItem)
  2276.             {
  2277.                 case kPrefsMenuItem:
  2278.                     HandlePrefsDialog();
  2279.                     break;
  2280.             }
  2281.         case kViewMenuID:
  2282.             switch (menuItem)
  2283.             {
  2284.                 case kSmallIconMenuItem:
  2285.                 case kIconMenuItem:
  2286.                     HandleViewSize(menuItem);
  2287.                     break;
  2288.             }
  2289.             break;
  2290.     }
  2291.     HiliteMenu(0);      // unhilight menu title
  2292. }
  2293.  
  2294. //////////////////////////////////////////////////////////////////////////////
  2295. //
  2296. //    OpenDropFolder
  2297. //
  2298. //    Send an appleevent to the finder to open our drop folder
  2299. //
  2300. OSErr OpenDropFolder(void)
  2301. {
  2302.     AppleEvent                send;
  2303.     AppleEvent                reply;
  2304.     AEDesc                    target;
  2305.     ProcessSerialNumber        psn;
  2306.     ProcessInfoRecPtr        pInfo;
  2307.     SInt32                    dirID;
  2308.     OSErr                    err;
  2309.  
  2310.     psn.highLongOfPSN = kNoProcess;
  2311.     psn.lowLongOfPSN = kNoProcess;
  2312.     pInfo = (ProcessInfoRecPtr) NewPtr(sizeof(ProcessInfoRec));
  2313.     if (pInfo == nil)
  2314.         return memFullErr;
  2315.     pInfo->processInfoLength = sizeof(ProcessInfoRec);
  2316.     pInfo->processName = nil;
  2317.     pInfo->processAppSpec = nil;
  2318.     do {
  2319.         err = GetNextProcess(&psn);
  2320.         GetProcessInformation(&psn, pInfo);
  2321.     }
  2322.     while ((err == noErr) && (pInfo->processType != 'FNDR'));
  2323.     DisposePtr((Ptr) pInfo);
  2324.     
  2325.     err = FSpDirCreate(&gpFWXAppData->fwixReceiveFolder, smSystemScript, &dirID);
  2326.     if (err == dupFNErr)
  2327.         err = noErr;
  2328.         
  2329.     if (err == noErr) {
  2330.                 
  2331.         err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &target);
  2332.         if (err != noErr)
  2333.             return err;
  2334.  
  2335.         err = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &target, 
  2336.                 kAutoGenerateReturnID, kAnyTransactionID, &send);
  2337.         
  2338.         err = AEPutParamPtr(&send, keyDirectObject, typeFSS, (Ptr) &(gpFWXAppData->fwixReceiveFolder), sizeof(FSSpec));
  2339.  
  2340.         err = AESend(&send, &reply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  2341.                     kAENormalPriority, kAEDefaultTimeout, nil, nil);
  2342.  
  2343.         AEDisposeDesc(&target);
  2344.         AEDisposeDesc(&send);
  2345.     }
  2346.     SetFrontProcess(&psn);
  2347.     
  2348.     return err;
  2349. }
  2350.  
  2351. //////////////////////////////////////////////////////////////////////////////
  2352. //
  2353. //    OpenSharingSetup
  2354. //
  2355. //    Send an appleevent to the finder to open the Sharing Setup Control Panel
  2356. //
  2357. static OSErr OpenSharingSetup(void)
  2358. {
  2359.     AppleEvent                send;
  2360.     AppleEvent                reply;
  2361.     AEDesc                    target;
  2362.     ProcessSerialNumber        psn;
  2363.     ProcessInfoRecPtr        pInfo;
  2364.     FSSpec                    spec;
  2365.     SInt32                    dirID;
  2366.     SInt16                    vRefNum;
  2367.     OSErr                    err;
  2368.  
  2369.     psn.highLongOfPSN = kNoProcess;
  2370.     psn.lowLongOfPSN = kNoProcess;
  2371.     pInfo = (ProcessInfoRecPtr) NewPtr(sizeof(ProcessInfoRec));
  2372.     if (pInfo == nil)
  2373.         return memFullErr;
  2374.     pInfo->processInfoLength = sizeof(ProcessInfoRec);
  2375.     pInfo->processName = nil;
  2376.     pInfo->processAppSpec = nil;
  2377.     do {
  2378.         err = GetNextProcess(&psn);
  2379.         GetProcessInformation(&psn, pInfo);
  2380.     }
  2381.     while ((err == noErr) && (pInfo->processType != 'FNDR'));
  2382.     DisposePtr((Ptr) pInfo);
  2383.     
  2384.     if (err == noErr) {
  2385.                 
  2386.         err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &target);
  2387.         if (err != noErr)
  2388.             return err;
  2389.  
  2390.         err = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &target, 
  2391.                 kAutoGenerateReturnID, kAnyTransactionID, &send);
  2392.         
  2393.         err = FindFolder(kOnSystemDisk, kControlPanelFolderType, kDontCreateFolder,
  2394.                         &vRefNum, &dirID);
  2395.         err = FSMakeFSSpec(vRefNum, dirID, "\pSharing Setup", &spec);
  2396.         if (err == fnfErr)
  2397.             err = FSMakeFSSpec(vRefNum, dirID, "\pFile Sharing", &spec);
  2398.         err = AEPutParamPtr(&send, keyDirectObject, typeFSS, (Ptr) &spec, sizeof(FSSpec));
  2399.  
  2400.         err = AESend(&send, &reply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  2401.                     kAENormalPriority, kAEDefaultTimeout, nil, nil);
  2402.  
  2403.         AEDisposeDesc(&target);
  2404.         AEDisposeDesc(&send);
  2405.     }
  2406.     SetFrontProcess(&psn);
  2407.     
  2408.     return err;
  2409. }
  2410.  
  2411. ////////////////////////////////////////////////////////////////////////////////
  2412. //
  2413. //    HandleViewSize
  2414. //
  2415. //    Handle the window view size command.
  2416. //
  2417. static OSErr HandleViewSize(
  2418.     SInt16                    whichMenuItem)
  2419. {
  2420.     MenuHandle                hMenu;
  2421.     WindowPtr                pWin;
  2422.     WindowDataPtr            pWinData;
  2423.     OSErr                    err = noErr;
  2424.     
  2425.     pWin = gpFWXAppData->pSenderWindow;
  2426.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2427.     if (pWinData == nil)
  2428.         return memFullErr;
  2429.     
  2430.     hMenu = GetMenuHandle(kViewMenuID);
  2431.     if ((pWinData->windowView == kLargeIconView) && (whichMenuItem == kSmallIconMenuItem))
  2432.     {
  2433.         pWinData->windowView = kSmallIconView;
  2434.         gpFWXAppData->fwixPrefs |= kIconView;
  2435.         SetItemMark(hMenu, kSmallIconMenuItem, checkMark);
  2436.         SetItemMark(hMenu, kIconMenuItem, noMark);
  2437.         AdjustNodeIcons(pWinData, &pWin->portRect);
  2438.         AdjustScrollBars(pWin, false);
  2439.         UpdatePrefsFile();
  2440.     }
  2441.     else if ((pWinData->windowView == kSmallIconView) && (whichMenuItem == kIconMenuItem))
  2442.     {
  2443.         pWinData->windowView = kLargeIconView;
  2444.         gpFWXAppData->fwixPrefs &= ~kIconView;
  2445.         SetItemMark(hMenu, kSmallIconMenuItem, noMark);
  2446.         SetItemMark(hMenu, kIconMenuItem, checkMark);
  2447.         AdjustNodeIcons(pWinData, &pWin->portRect);
  2448.         AdjustScrollBars(pWin, false);
  2449.         UpdatePrefsFile();
  2450.     }
  2451.     InvalRect(&pWin->portRect);
  2452.     return err;    
  2453. }
  2454.  
  2455. ////////////////////////////////////////////////////////////////////////////////
  2456. //
  2457. //    HandleMouseDownEvent
  2458. //
  2459. //    This routine handles mouse down events.
  2460. //
  2461. static void HandleMouseDownEvent(
  2462.     EventRecord                    *pEventRecord)
  2463. {
  2464.     static ControlActionUPP        cupp;
  2465.     GrafPtr                        curPort;
  2466.     WindowRef                    theWindow;
  2467.     Rect                        tempRect;
  2468.     ControlHandle                hControl;
  2469.     Point                        mouse;
  2470.     SInt16                        whichPart;
  2471.     SInt16                        cntlPart;
  2472.     
  2473.     whichPart = FindWindow(pEventRecord->where, &theWindow);
  2474.     
  2475.     switch (whichPart) {
  2476.         case inSysWindow:  // desk accessory window
  2477.             SystemClick(pEventRecord, theWindow);
  2478.             break;
  2479.  
  2480.         case inMenuBar:
  2481.             HandleMenuCommand(MenuSelect(pEventRecord->where));
  2482.             break;
  2483.  
  2484.         case inDrag:
  2485.             tempRect = qd.screenBits.bounds;
  2486.             if (gpFWXAppData->pSenderWindow != FrontWindow())
  2487.             {
  2488.                 // progress bar would be up, it is movable modal
  2489.                 if (theWindow == FrontWindow())
  2490.                     DragWindow(theWindow, pEventRecord->where, &tempRect);
  2491.                 else
  2492.                     SysBeep(0);
  2493.             } else
  2494.                 DragWindow(theWindow, pEventRecord->where, &tempRect);
  2495.             SaveWindowPos(theWindow);
  2496.             break;
  2497.  
  2498.         case inGoAway:
  2499.             if (TrackGoAway(theWindow, pEventRecord->where)) {
  2500.                 HideWindow(theWindow);
  2501.                 EnableItem(GetMenuHandle(kFileMenuID), kOpenMenuItem);
  2502.                 DisableItem(GetMenuHandle(kFileMenuID), kCloseMenuItem);
  2503.                 DisableItem(GetMenuHandle(kViewMenuID), 0);
  2504.                 DrawMenuBar();
  2505.             }
  2506.             break;
  2507.  
  2508.         case inGrow:
  2509.             HandleGrowWindow(theWindow, pEventRecord->where);
  2510.             break;
  2511.             
  2512.         case inZoomIn:
  2513.         case inZoomOut:
  2514.             if (TrackBox(theWindow, pEventRecord->where, whichPart))
  2515.                 HandleZoomWindow(theWindow, whichPart);
  2516.             break;
  2517.  
  2518.         case inContent:
  2519.                     GetPort(&curPort);
  2520.                     SetPort(theWindow);
  2521.                     mouse = pEventRecord->where;
  2522.                     GlobalToLocal(&mouse);
  2523.                     cntlPart = FindControl(mouse, theWindow, &hControl);    
  2524.             if (cntlPart)
  2525.             {
  2526.                 if (gpFWXAppData->pSenderWindow == FrontWindow())
  2527.                 {
  2528.                     // handle user click in one of the sender window scroll bars
  2529.                     if (cntlPart == kControlIndicatorPart)
  2530.                         HandleThumbScroll(hControl, theWindow, mouse);
  2531.                     else
  2532.                     {
  2533.                         if (!cupp)
  2534.                             cupp = NewControlActionProc(HandleScrollAction);
  2535.                         TrackControl(hControl, mouse, cupp);
  2536.                     }
  2537.                 }
  2538.                 else
  2539.                 {    // progress bar is up, make it modal, check for stop button
  2540.                     if (theWindow != FrontWindow())
  2541.                         SysBeep(0);
  2542.                     else
  2543.                     {
  2544.                         if (cntlPart == kControlButtonPart)
  2545.                         {
  2546.                             if (TrackControl(hControl, mouse, nil))
  2547.                                 StopTransfer(nil);
  2548.                         }
  2549.                     }
  2550.                 }
  2551.             }
  2552.             SetPort(curPort);
  2553.             break;
  2554.     }
  2555. }
  2556.  
  2557. ////////////////////////////////////////////////////////////////////////////////
  2558. //
  2559. //    HandleThumbScroll
  2560. //
  2561. //    Handle scrolling by the thumb button.
  2562. //
  2563. static pascal void HandleThumbScroll (
  2564.     ControlHandle        scrollCtl,
  2565.     WindowPtr            pWin,
  2566.     Point                mouse)
  2567. {
  2568.     WindowDataPtr        pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2569.     RgnHandle            updateRgn;
  2570.     Rect                drawRect;
  2571.     SInt16                value, h, v;
  2572.     SInt16                cntlPart;
  2573.     
  2574.     value = GetControlValue(scrollCtl);
  2575.     cntlPart = TrackControl(scrollCtl, mouse, nil);
  2576.     if (cntlPart)
  2577.     {
  2578.         value -= GetControlValue(scrollCtl);
  2579.         if (value != 0)
  2580.         {
  2581.             h = v = 0;
  2582.             if (scrollCtl == pWinData->hVScrollBar)
  2583.                 v = value;
  2584.             else
  2585.                 h = value;
  2586.                 
  2587.             drawRect = pWin->portRect;
  2588.             drawRect.bottom -= kScrollBarAdjust;
  2589.             drawRect.right -= kScrollBarAdjust;
  2590.             ScrollRect(&drawRect, h, v, updateRgn = NewRgn());
  2591.             InvalRgn(updateRgn);
  2592.             DisposeRgn(updateRgn);
  2593.             BeginUpdate(pWin);
  2594.             DrawWindow(pWin);
  2595.             EndUpdate(pWin);
  2596.         }
  2597.     }
  2598. }
  2599.  
  2600. ////////////////////////////////////////////////////////////////////////////////
  2601. //
  2602. //    HandleScrollAction
  2603. //
  2604. //    Handle scrolling window.
  2605. //
  2606. static pascal void HandleScrollAction (
  2607.     ControlHandle        scrollCtl,
  2608.     SInt16                part)
  2609. {
  2610.     WindowPtr            pWin = gpFWXAppData->pSenderWindow;
  2611.     WindowDataPtr        pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2612.     RgnHandle            updateRgn;
  2613.     Rect                drawRect;
  2614.     SInt16                delta, value, h, v;
  2615.     SInt16                oldValue, max;
  2616.  
  2617.     if ((pWinData != nil) && part)
  2618.     {
  2619.         switch (part)
  2620.         {
  2621.             case kControlUpButtonPart:
  2622.             case kControlDownButtonPart:
  2623.                 delta = 5;
  2624.                 break;
  2625.  
  2626.             case kControlPageUpPart:
  2627.             case kControlPageDownPart:
  2628.                 if (scrollCtl == pWinData->hHScrollBar)
  2629.                     delta = pWin->portRect.right - pWin->portRect.left - kScrollBarAdjust;
  2630.                 else
  2631.                     delta = pWin->portRect.bottom - pWin->portRect.top - kScrollBarAdjust;                    
  2632.                 break;
  2633.             
  2634.             // handle cases generated by keyboard input
  2635.             case kPageUpKey:
  2636.             case kPageDownKey:
  2637.                 delta = pWin->portRect.bottom - pWin->portRect.top - kScrollBarAdjust;
  2638.                 break;
  2639.             
  2640.             case kHomeKey:
  2641.                 delta = -32000;        // a large enough number to make value = 0
  2642.                 break;
  2643.             
  2644.             case kEndKey:
  2645.                 delta = 32000;        // a large enough number to make value = max
  2646.                 break;
  2647.         }
  2648.  
  2649.         // reverse direction for scrolling up
  2650.         if ((part == kControlUpButtonPart) || (part == kControlPageUpPart) || (part == kPageUpKey))
  2651.             delta = -delta;
  2652.  
  2653.         // pin scroll value at min or max.
  2654.         oldValue = GetControlValue(scrollCtl);
  2655.         value = oldValue + delta;
  2656.         if (value < 0)
  2657.             value = 0;
  2658.         max = GetControlMaximum(scrollCtl);
  2659.         if (value > max)
  2660.             value = max;
  2661.  
  2662.         if (value != oldValue)
  2663.         {
  2664.             drawRect = pWin->portRect;
  2665.             drawRect.bottom -= kScrollBarAdjust;
  2666.             drawRect.right -= kScrollBarAdjust;
  2667.             SetControlValue(scrollCtl, value);
  2668.             h = oldValue - value;
  2669.             v = 0;
  2670.             if (scrollCtl == pWinData->hVScrollBar)
  2671.             {
  2672.                 v = h;
  2673.                 h = 0;
  2674.             }
  2675.             ScrollRect(&drawRect, h, v, updateRgn = NewRgn());
  2676.             InvalRgn(updateRgn);
  2677.             DisposeRgn(updateRgn);
  2678.             BeginUpdate(pWin);
  2679.             DrawWindow(pWin);
  2680.             EndUpdate(pWin);
  2681.         }
  2682.     }
  2683. }
  2684.  
  2685. ////////////////////////////////////////////////////////////////////////////////
  2686. //
  2687. //    HandleZoomWindow
  2688. //
  2689. //    Zoom the window.
  2690. //
  2691. static void HandleZoomWindow(
  2692.     WindowPtr            pWin,
  2693.     SInt16                whichZoom)
  2694. {
  2695.     WindowDataPtr        pWinData;
  2696.     Rect                zoomRect;
  2697.     SInt16                vSize, hSize;
  2698.     SInt16                row, column;
  2699.  
  2700.     if (whichZoom == inZoomOut)
  2701.     {
  2702.         pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2703.         if (pWinData != nil)
  2704.         {
  2705.             if (pWinData->windowView == kLargeIconView)
  2706.             {
  2707.                 row = pWinData->numRecvNodes % kLargeRowCount;
  2708.                 column = pWinData->numRecvNodes / kLargeRowCount;
  2709.                 if (column == 0)
  2710.                     vSize = row * kLargeVSize;
  2711.                 else
  2712.                     vSize = kLargeRowCount * kLargeVSize;
  2713.                 hSize = (column + 1) * kLargeHSize;
  2714.             }
  2715.             else
  2716.             {    
  2717.                 row = pWinData->numRecvNodes % kSmallRowCount;
  2718.                 column = pWinData->numRecvNodes / kSmallRowCount;
  2719.                 if (column == 0)
  2720.                     vSize = row * kSmallVSize;
  2721.                 else
  2722.                     vSize = kSmallRowCount * kSmallVSize;
  2723.                 // make sure there is enough room for scroll bars
  2724.                 if (vSize < kLargeVSize)
  2725.                     vSize = kLargeVSize;
  2726.                 hSize = (column + 1) * kSmallHSize;
  2727.             }
  2728.         }
  2729.         zoomRect = (**((WStateDataHandle) ((WindowPeek) pWin)->dataHandle)).userState;
  2730.         zoomRect.bottom = zoomRect.top + vSize + kScrollBarWidth;
  2731.         zoomRect.right = zoomRect.left + hSize + kScrollBarWidth;
  2732.         (**((WStateDataHandle) ((WindowPeek) pWin)->dataHandle)).stdState = zoomRect;
  2733.     }
  2734.     ZoomWindow(pWin, whichZoom, FrontWindow() == pWin);
  2735.     AdjustScrollBars(pWin, true);
  2736.     InvalRect(&pWin->portRect);
  2737.     SaveWindowPos(pWin);
  2738. }
  2739.  
  2740. ////////////////////////////////////////////////////////////////////////////////
  2741. //
  2742. //    HandleGrowWindow
  2743. //
  2744. //    Grow the window.
  2745. //
  2746. static void HandleGrowWindow(
  2747.     WindowPtr            pWin,
  2748.     Point                clickLoc)
  2749. {
  2750.     Rect                limitRect;
  2751.     SInt32                growSize;
  2752.     
  2753.     SetRect(&limitRect, kLargeVSize, kLargeVSize, 3000, 3000);
  2754.     growSize = GrowWindow(pWin, clickLoc, &limitRect);
  2755.     if (growSize != 0)
  2756.     {
  2757.         SizeWindow(pWin, LoWord(growSize), HiWord(growSize), true);
  2758.         AdjustScrollBars(pWin, true);
  2759.         InvalRect(&pWin->portRect);
  2760.         SaveWindowPos(pWin);
  2761.     }
  2762. }
  2763.  
  2764. ////////////////////////////////////////////////////////////////////////////////
  2765. //
  2766. //    StopTransfer
  2767. //
  2768. //    Handle user stopping file transfer.
  2769. //
  2770. void StopTransfer (
  2771.     RecvNodePtr                    pNode)
  2772. {
  2773.     FWXPacketPtr                pPktInfo;        // puts a packet structure on ioBuffer
  2774.     IOParamPtr                    pIOPb;            // write parameter block
  2775.     TxFSSpecPtr                    pTxItem;
  2776.     NodeSendItemPtr                pSendItem, pTempItem;
  2777.     
  2778.     if (pNode != nil)
  2779.     {
  2780.         if (pNode->pTxItemList != nil)
  2781.         {
  2782.             pSendItem = pNode->pTxItemList;
  2783.             while (pSendItem != nil)
  2784.             {
  2785.                 pTempItem = pSendItem;
  2786.                 pSendItem = pSendItem->pNextSendItem;
  2787.                 DisposePtr((Ptr) pTempItem);
  2788.             }
  2789.             pNode->pTxItemList = nil;
  2790.         }
  2791.     }
  2792.             
  2793.     if (gSendingFile || gCheckingTransfer)
  2794.     {
  2795.         gCheckingTransfer = false;
  2796.     gForkComplete = true;
  2797.     gForkWriteComplete = true;
  2798.     CleanupCopyDialog(FrontWindow());
  2799.     if (gSendingDataFork || gSendingResFork)
  2800.     {
  2801.         gSendingDataFork = false;
  2802.         gSendingResFork = false;
  2803.         FSClose(gCurForkRefNum);
  2804.     }
  2805.     
  2806.         if (gSendingFile)
  2807.         {
  2808.             gSendingFile = false;
  2809.             
  2810.     // send file stopped to receiver
  2811.     FWIXDequeue ((QElemPtr *) &pIOPb, &gFWControlQHdr);
  2812.     if (pIOPb != nil)
  2813.     {
  2814.         SetupFWControlPB(pIOPb);
  2815.                 
  2816.         pPktInfo = (FWXPacketPtr) pIOPb->ioBuffer;
  2817.         pPktInfo->packetType = kTransferStopped;
  2818.         pIOPb->ioMisc = (Ptr) kTransferStopped;
  2819.         pIOPb->ioReqCount = 4;                // just packet header
  2820.  
  2821.         CallFWXNode(pIOPb);
  2822.     }
  2823.     }
  2824.     }
  2825.  
  2826.     // dequeue and dispose of all file queue entries
  2827.     pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  2828.     while (pTxItem != nil)
  2829.     {
  2830.         Dequeue((QElemPtr) pTxItem, &gSendQHdr);
  2831.         DisposePtr((Ptr) pTxItem->pFSSpec);
  2832.         DisposePtr((Ptr) pTxItem);
  2833.  
  2834.         // get another queue item
  2835.         pTxItem = (TxFSSpecPtr) gSendQHdr.qHead;
  2836.     }
  2837. }
  2838.  
  2839. ////////////////////////////////////////////////////////////////////////////////
  2840. //
  2841. //    HandleUpdateEvent
  2842. //
  2843. //    This routine handles update events.
  2844. //
  2845. void HandleUpdateEvent (
  2846.     EventRecord            *pEventRecord)
  2847. {
  2848.     WindowPtr            pWin;
  2849.     GrafPtr                curPort;
  2850.  
  2851.     pWin = (WindowPtr) pEventRecord->message;
  2852.  
  2853.     GetPort(&curPort);
  2854.     SetPort(pWin);
  2855.     if (pWin == gpFWXAppData->pSenderWindow)
  2856.     {
  2857.         BeginUpdate(pWin);        
  2858.             DrawWindow(pWin);
  2859.         EndUpdate(pWin);
  2860.     }
  2861.     else
  2862.     {
  2863.         BeginUpdate(pWin);
  2864.         UpdateDialog(pWin, pWin->visRgn);
  2865.         EndUpdate(pWin);
  2866.     }
  2867.     SetPort(curPort);
  2868. }
  2869.  
  2870. ////////////////////////////////////////////////////////////////////////////////
  2871. //
  2872. //    HandleKeyEvent
  2873. //
  2874. //    This routine handles key events. The only ones we handle are menu shortcuts
  2875. //    and stopping the transfer shortcuts.
  2876. //
  2877. static void HandleKeyEvent (
  2878.     EventRecord            *pEventRecord)
  2879. {
  2880.     WindowPtr            pWin;
  2881.     WindowDataPtr        pWinData;
  2882.     char                key;
  2883.     
  2884.     key = pEventRecord->message & charCodeMask;
  2885.  
  2886.     if ((pEventRecord->modifiers & cmdKey) && (pEventRecord->what == keyDown))
  2887.     {
  2888.         if ((gSendingFile || gCheckingTransfer) && (key == kPeriodKey))
  2889.             StopTransfer(nil);
  2890.         else
  2891.             HandleMenuCommand(MenuKey(key));
  2892.     }
  2893.     
  2894.     if ((gSendingFile || gCheckingTransfer) && (key == kEscapeKey))
  2895.         StopTransfer(nil);
  2896.     
  2897.     if ((key == kPageUpKey) || (key == kPageDownKey) || (key == kHomeKey) || (key == kEndKey))
  2898.     {
  2899.         pWin = FrontWindow();
  2900.         if (pWin == gpFWXAppData->pSenderWindow)
  2901.         {
  2902.             pWinData = (WindowDataPtr) GetWRefCon(pWin);
  2903.             HandleScrollAction(pWinData->hVScrollBar, key);
  2904.         }
  2905.     }
  2906. }
  2907.  
  2908. ////////////////////////////////////////////////////////////////////////////////
  2909. //
  2910. // HandleOSEvent
  2911. //
  2912. // This routine handles OS events.
  2913. //
  2914.  
  2915. static void HandleOSEvent(
  2916.     EventRecord            *pEventRecord)
  2917. {
  2918.     UInt32                osEventType;
  2919.  
  2920.     // Get the OS event type.
  2921.     osEventType = pEventRecord->message >> 24;
  2922.  
  2923.     switch (osEventType)
  2924.     {
  2925.         case suspendResumeMessage:
  2926.             if (pEventRecord->message & resumeFlag)
  2927.             {
  2928.                 gpFWXAppData->inForeground = true;
  2929.  
  2930.                 if (gpFWXAppData->pNotifyRec->nmRefCon == kNotificationPosted)
  2931.                 {
  2932.                     NMRemove(gpFWXAppData->pNotifyRec);
  2933.                     gpFWXAppData->pNotifyRec->nmRefCon = kNoNotificationPosted;
  2934.                 }
  2935.             }
  2936.             else
  2937.                 gpFWXAppData->inForeground = false;
  2938.             
  2939.             HandleActivate(FrontWindow(), gpFWXAppData->inForeground);
  2940.             break;
  2941.     }
  2942. }
  2943.  
  2944.  
  2945. //////////////////////////////////////////////////////////////////////////////
  2946. //
  2947. //    HandleEvent
  2948. //
  2949. //    main event handling routine
  2950. //
  2951.  
  2952. static void HandleEvent (
  2953.     EventRecord        *theEvent)
  2954. {
  2955.     Point            point;
  2956.  
  2957.     switch (theEvent->what) {
  2958.         case mouseDown:
  2959.             HandleMouseDownEvent(theEvent);
  2960.             break;
  2961.  
  2962.         case updateEvt:
  2963.             HandleUpdateEvent(theEvent);
  2964.             break;
  2965.                     
  2966.         case keyDown:
  2967.         case autoKey:
  2968.             HandleKeyEvent(theEvent);
  2969.             break;
  2970.             
  2971.         case kHighLevelEvent:
  2972.             AEProcessAppleEvent(theEvent);
  2973.             break;
  2974.                     
  2975.         case osEvt:
  2976.             HandleOSEvent(theEvent);
  2977.             break;
  2978.             
  2979.         case diskEvt:
  2980.             if ((theEvent->message >> 16) != noErr) {
  2981.                 SetPt (&point, kDILeft, kDITop);
  2982.                 DIBadMount (point, theEvent->message);
  2983.             }
  2984.             break;
  2985.  
  2986.         case activateEvt:
  2987.             HandleActivate((WindowPtr) theEvent->message, (theEvent->modifiers & activeFlag) != 0);
  2988.             break;
  2989.     }
  2990. }
  2991.  
  2992. //////////////////////////////////////////////////////////////////////////////
  2993. //
  2994. //    HandleActivate
  2995. //
  2996. //    Take care of activating/deactivating, mainly just handling controls
  2997. //    and grow box.
  2998. //
  2999. static void HandleActivate(
  3000.     WindowPtr                pWin,
  3001.     Boolean                    becomingActive)
  3002. {
  3003.     WindowDataPtr            pWinData;
  3004.     
  3005.     if (IsAppWindow(pWin))
  3006.     {
  3007.         if (becomingActive)
  3008.         {
  3009.             gpFWXAppData->inForeground = true;
  3010.             if (pWin == gpFWXAppData->pSenderWindow)
  3011.             {
  3012.                 pWinData = (WindowDataPtr) GetWRefCon(pWin);
  3013.                 ShowControl(pWinData->hHScrollBar);
  3014.                 ShowControl(pWinData->hVScrollBar);
  3015.             }
  3016.             InvalRect(&pWin->portRect);
  3017.         }
  3018.         else
  3019.         {
  3020.             gpFWXAppData->inForeground = false;
  3021.             if (pWin == gpFWXAppData->pSenderWindow)
  3022.             {
  3023.                 pWinData = (WindowDataPtr) GetWRefCon(pWin);
  3024.                 HideControl(pWinData->hHScrollBar);
  3025.                 HideControl(pWinData->hVScrollBar);
  3026.                 DrawGrowIcon(pWin);
  3027.             }
  3028.         }
  3029.     }
  3030. }
  3031.  
  3032. //////////////////////////////////////////////////////////////////////////////
  3033. //
  3034. //    IsAppWindow
  3035. //
  3036. //    Check to see if our window needs handling for activate event.
  3037. //
  3038. static Boolean IsAppWindow(
  3039.     WindowPtr                pWin)
  3040. {
  3041.     SInt16                    windowKind;
  3042.  
  3043.     if (pWin == nil)
  3044.         return false;
  3045.     else {
  3046.         windowKind = ((WindowPeek) pWin)->windowKind;
  3047.         return (windowKind == userKind);
  3048.     }
  3049. }
  3050.  
  3051. //////////////////////////////////////////////////////////////////////////////
  3052. //
  3053. //    HandleIdle
  3054. //
  3055. //    At idle time check for processing send/receive information that may be
  3056. //    halted.
  3057. //
  3058. void HandleIdle(void)
  3059. {
  3060.     RecvNodePtr                pRecvNode;
  3061.     CurFileInfoPtr            pTxInfo;
  3062.     OSErr                    err;
  3063.     
  3064.     // received some data, handle it
  3065.     if (gReceiveQHdr.qHead != nil) {
  3066.         HandleReceive();
  3067.     }
  3068.     
  3069.     if (gSendingFile)
  3070.         UpdateProgressBar(FrontWindow(), kProgressBarUserItem);
  3071.     
  3072.     // if a file is being sent and end of file has been read, handle it
  3073.     if (gSendingDataFork || gSendingResFork)
  3074.     {
  3075.         if (gForkComplete && gForkWriteComplete)
  3076.         {
  3077.             HandleForkReadComplete();
  3078.         }
  3079.     }
  3080.  
  3081.     // if sending errors, show the alert and other routines
  3082.     // will take care of the clean up
  3083.     // JKL *** you sure about this?, no!
  3084.     if (gSendError != 0) {
  3085.         gSendError = (FWXNodeID) 0;
  3086.         err = GetNodeInfo(gSendError, &pRecvNode);
  3087.         if (err == noErr) {
  3088.             ParamText(pRecvNode->nodeName, "\p","\p","\p");
  3089.             HandleCautionAlert(kCommunicationErrorAlertID);
  3090.         }
  3091.     }
  3092.     
  3093.     // if receiving error show the alert and also clean up
  3094.     // pending receive
  3095.     if (gReceiveError != 0) {
  3096.         gReceiveError = (FWXNodeID) 0;
  3097.         err = GetCurFileInfo(gReceiveError, &pTxInfo, false);
  3098.         if (err == noErr)
  3099.             HandleStopTransfer(pTxInfo);
  3100.         err = GetNodeInfo(gSendError, &pRecvNode);
  3101.         if (err == noErr) {
  3102.             ParamText(pRecvNode->nodeName, "\p","\p","\p");
  3103.             HandleCautionAlert(kCommunicationErrorAlertID);
  3104.         }
  3105.     }
  3106. }
  3107.  
  3108. //////////////////////////////////////////////////////////////////////////////
  3109. //
  3110. //    HandleCautionAlert
  3111. //
  3112. //    Routine to call caution alerts
  3113. //
  3114. SInt16 HandleCautionAlert (
  3115.     SInt16                alertResID)
  3116. {
  3117.     UniversalProcPtr    alertFilterProc = NewModalFilterProc(HandleAlertEventFilter);
  3118.     SInt16                itemHit;
  3119.  
  3120.     itemHit = CautionAlert(alertResID, alertFilterProc);
  3121.     DisposeRoutineDescriptor(alertFilterProc);
  3122.     return itemHit;
  3123. }
  3124.  
  3125. //////////////////////////////////////////////////////////////////////////////
  3126. //
  3127. //    HandleStopAlert
  3128. //
  3129. //    Routine to call stop alerts
  3130. //
  3131. SInt16 HandleStopAlert (
  3132.     SInt16                alertResID)
  3133. {
  3134.     UniversalProcPtr    alertFilterProc = NewModalFilterProc(HandleAlertEventFilter);
  3135.     SInt16                itemHit;
  3136.  
  3137.     itemHit = StopAlert(alertResID, alertFilterProc);
  3138.     DisposeRoutineDescriptor(alertFilterProc);
  3139.     return itemHit;
  3140. }
  3141.  
  3142. //////////////////////////////////////////////////////////////////////////////
  3143. //
  3144. //    HandleNoteAlert
  3145. //
  3146. //    Routine to call note alerts
  3147. //
  3148. SInt16 HandleNoteAlert (
  3149.     SInt16                alertResID)
  3150. {
  3151.     UniversalProcPtr    alertFilterProc = NewModalFilterProc(HandleAlertEventFilter);
  3152.     SInt16                itemHit;
  3153.  
  3154.     itemHit = NoteAlert(alertResID, alertFilterProc);
  3155.     DisposeRoutineDescriptor(alertFilterProc);
  3156.     return itemHit;
  3157. }
  3158.  
  3159. //////////////////////////////////////////////////////////////////////////////
  3160. //
  3161. //    HandleAlert
  3162. //
  3163. //    Routine to call alerts
  3164. //
  3165. SInt16 HandleAlert (
  3166.     SInt16                alertResID)
  3167. {
  3168.     UniversalProcPtr    alertFilterProc = NewModalFilterProc(HandleAlertEventFilter);
  3169.     SInt16                itemHit;
  3170.  
  3171.     itemHit = Alert(alertResID, alertFilterProc);
  3172.     DisposeRoutineDescriptor(alertFilterProc);
  3173.     return itemHit;
  3174. }
  3175.  
  3176. //////////////////////////////////////////////////////////////////////////////
  3177. //
  3178. //    HandleAlertEventFilter
  3179. //
  3180. //    Handles alert filter events
  3181. //
  3182. static pascal Boolean HandleAlertEventFilter(
  3183.     DialogPtr            pDlog,
  3184.     EventRecord            *pEvent,
  3185.     SInt16                *itemHit)
  3186. {
  3187.     Handle                item;
  3188.     Rect                box;
  3189.     UInt32                finalTicks;
  3190.     SInt16                itemType;
  3191.     UInt8                key;
  3192.     Boolean                handledIt;
  3193.     
  3194.     handledIt = false;
  3195.     
  3196.     switch (pEvent->what)
  3197.     {
  3198.         case keyDown:
  3199.             key = pEvent->message & charCodeMask;
  3200.             
  3201.             if (key == kReturnKey || key == kEnterKey)
  3202.             {
  3203.                 GetDialogItem(pDlog, kOKButton, &itemType, &item, &box);
  3204.                 HiliteControl((ControlHandle) item, kControlButtonPart);
  3205. #if ETO_Build
  3206.                 Delay(8, (long *)&finalTicks);
  3207. #else
  3208.                 Delay(8, &finalTicks);
  3209. #endif
  3210.                 HiliteControl((ControlHandle) item, 0);
  3211.                 handledIt = true;
  3212.                 *itemHit = kOKButton;
  3213.             }
  3214.             break;
  3215.         
  3216.         case nullEvent:
  3217.             HandleIdle();
  3218.             break;
  3219.         
  3220.         case updateEvt:
  3221.             HandleUpdateEvent(pEvent);
  3222.             break;
  3223.     }
  3224.     return handledIt;
  3225. }
  3226.  
  3227. //////////////////////////////////////////////////////////////////////////////
  3228. //
  3229. //    FWXMain
  3230. //
  3231. //    main routine for FWiX
  3232. //
  3233. #ifdef __MWERKS__
  3234. void main()
  3235. #else
  3236. void FWXMain()
  3237. #endif
  3238. {
  3239.     EventRecord        theEvent;
  3240.     OSErr            err = noErr;
  3241.     Boolean            gotEvent;
  3242.     
  3243.     err = FWXInit();
  3244.     
  3245.     if (err == noErr)
  3246.     {
  3247.         do
  3248.         {
  3249.             // Get any FWX events.
  3250.             GetNextFWXClientEvent (gpFWXAppData->fwxClientID);
  3251.             
  3252.             gotEvent = WaitNextEvent(everyEvent, &theEvent, 0, nil);
  3253.             
  3254.             if (gotEvent)
  3255.                 HandleEvent(&theEvent);
  3256.             else
  3257.                 HandleIdle();
  3258.             
  3259.         } while (!gpFWXAppData->quitFlag);
  3260.     }
  3261.     else if (err == memFullErr)
  3262.     {
  3263.         HandleStopAlert(kMemoryErrorAlertID);
  3264.     }
  3265.         
  3266.     FWXDispose ();
  3267. }
  3268.  
  3269. //////////////////////////////////////////////////////////////////////////////
  3270. //
  3271. //    SetupFWXNode
  3272. //
  3273. //    Register with the fam and get any currently connected nodes
  3274. //
  3275. static OSErr SetupFWXNode(void)
  3276. {
  3277.     UInt32                numFWXNodes;
  3278.     UInt32                nodeNum;
  3279.     FWXNodeID            *nodeIDList = nil;
  3280.     OSErr                err = noErr;
  3281.  
  3282.     err = RegisterFWXClientApplication(
  3283.                 &(gpFWXAppData->fwxClientID),
  3284.                 (UInt32) gpFWXAppData);
  3285.  
  3286.     // Get list of nodes.
  3287.     //zzz theoretically, new ones can be added while we're doing this.
  3288.     if (err == noErr) {
  3289.         err = GetFWXNodeList (nil, 0, &numFWXNodes);
  3290.     }
  3291.  
  3292.     if ((err == noErr) && (numFWXNodes > 0)) {
  3293.         nodeIDList = (FWXNodeID *) NewPtr(numFWXNodes * sizeof(FWXNodeID));
  3294.         if (nodeIDList != nil) {
  3295.             err = GetFWXNodeList(nodeIDList, numFWXNodes, &numFWXNodes);
  3296.         } else
  3297.             err = memFullErr;
  3298.     }
  3299.  
  3300.     if (err == noErr) {
  3301.         for (nodeNum = 0; nodeNum < numFWXNodes; nodeNum++) {
  3302.             SendDeviceAddedToSelf(nodeIDList[nodeNum]);
  3303.         }
  3304.     }
  3305.  
  3306.     if (nodeIDList != nil)
  3307.         DisposePtr((Ptr) nodeIDList);
  3308.             
  3309.     return err;
  3310. }
  3311.  
  3312.     
  3313. //////////////////////////////////////////////////////////////////////////////
  3314. //
  3315. //    SetupIOQueue
  3316. //
  3317. //    Setup the queueus. Initialize everything. Allocate buffers for reading
  3318. //    from files and writing to FireWire. The idea is to read then use the same
  3319. //    parameter block to write. The used queue is for taking a parameter block
  3320. //    and putting back on the free queue.
  3321. //
  3322. static OSErr SetupIOQueue(void)
  3323. {
  3324.     IOParamPtr                pIOPb;
  3325.     SInt16                    i;
  3326.     OSErr                    err = noErr;
  3327.     
  3328.     // init all of the queue headers
  3329.     gSendQHdr.qHead = nil;
  3330.     gSendQHdr.qTail = nil;
  3331.  
  3332.     gAESendQHdr.qHead = nil;
  3333.     gAESendQHdr.qTail = nil;
  3334.  
  3335.     gFileReadQHdr.qHead = nil;
  3336.     gFileReadQHdr.qTail = nil;
  3337.  
  3338.     gFWControlQHdr.qHead = nil;
  3339.     gFWControlQHdr.qTail = nil;
  3340.  
  3341.     gReceiveQHdr.qHead = nil;
  3342.     gReceiveQHdr.qTail = nil;
  3343.  
  3344.     gCurFileQHdr.qHead = nil;
  3345.     gCurFileQHdr.qTail = nil;
  3346.  
  3347.     queuesInitialized = true;
  3348.  
  3349.     // create file read parameter blocks and queue them on the file read queue
  3350.     for (i=0; i < kFileReadBufs; i++) {
  3351.         pIOPb = (IOParamPtr) NewPtr(sizeof(IOParam));
  3352.         if (pIOPb != nil) {
  3353.             HoldMemory ((Ptr) pIOPb, sizeof(IOParam));
  3354.         } else {
  3355.             FWDebugStr("\pOut of memory, SetupIOQ");
  3356.             err = memFullErr;
  3357.             break;
  3358.         }
  3359.                 
  3360.         // allocate data buffer        
  3361.         pIOPb->ioBuffer = NewPtr(kFileReadBufSize);
  3362.         if (pIOPb->ioBuffer != nil) {
  3363.             HoldMemory (pIOPb->ioBuffer, kFileReadBufSize);
  3364.         } else {
  3365.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  3366.             DisposePtr((Ptr) pIOPb);
  3367.             FWDebugStr("\pOut of memory, SetupIOQ");
  3368.             err = memFullErr;
  3369.             break;
  3370.         }
  3371.         
  3372.         Enqueue((QElemPtr) pIOPb, &gFileReadQHdr);
  3373.     }
  3374.     
  3375.     // create FW control parameter blocks and queue them on the FW control queue
  3376.     for (i=0; i < kFWControlParams; i++) {
  3377.         pIOPb = (IOParamPtr) NewPtr(sizeof(IOParam));
  3378.         if (pIOPb != nil) {
  3379.             HoldMemory ((Ptr) pIOPb, sizeof(IOParam));
  3380.         } else {
  3381.             FWDebugStr("\pOut of memory, SetupIOQ");
  3382.             err = memFullErr;
  3383.             break;
  3384.         }
  3385.                 
  3386.         pIOPb->ioBuffer = NewPtr(kFWControlParamBufferSize);
  3387.         if (pIOPb->ioBuffer != nil) {
  3388.             HoldMemory (pIOPb->ioBuffer, kFWControlParamBufferSize);
  3389.         } else {
  3390.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  3391.             DisposePtr((Ptr) pIOPb);
  3392.             FWDebugStr("\pOut of memory, SetupIOQ");
  3393.             err = memFullErr;
  3394.             break;
  3395.         }
  3396.         
  3397.         Enqueue((QElemPtr) pIOPb, &gFWControlQHdr);
  3398.     }
  3399.     
  3400.     return err;    
  3401. }    
  3402.  
  3403. //////////////////////////////////////////////////////////////////////////////
  3404. //
  3405. //    InitNotification
  3406. //
  3407. //    Set up our notify routine
  3408. //zzz must deallocate pNotifyRec.
  3409. //
  3410. static OSErr InitNotification (void)
  3411. {
  3412.     NMRecPtr        pNotifyRec;
  3413.     OSErr            err = noErr;
  3414.  
  3415.     pNotifyRec = (NMRecPtr) NewPtrClear(sizeof(NMRec));
  3416.     if (pNotifyRec == nil)
  3417.         err = memFullErr;
  3418.     else {
  3419.         pNotifyRec->qType = nmType;
  3420.         pNotifyRec->nmResp = NewNMProc(HandleNotifyResponse);
  3421.         pNotifyRec->nmMark = 1;
  3422.         pNotifyRec->nmRefCon = kNoNotificationPosted;
  3423.         UpdateNotification(pNotifyRec);
  3424.     }
  3425.     gpFWXAppData->pNotifyRec = pNotifyRec;
  3426.     return err;
  3427. }
  3428.     
  3429. //////////////////////////////////////////////////////////////////////////////
  3430. //
  3431. //    UpdateNotification
  3432. //
  3433. //    Setup notification parameters according to prefs
  3434. //zzz must deallocate nmStr, hRes?
  3435. //
  3436. void UpdateNotification (
  3437.     NMRecPtr            pNMRec)
  3438. {
  3439.     Handle                hRes;
  3440.     SInt16                curAttributes;
  3441.     OSErr                err;
  3442.     SInt8                notifyPrefs = gpFWXAppData->fwixPrefs;
  3443.     
  3444.     if (notifyPrefs & kNotifyFlash)
  3445.     {
  3446.         if (pNMRec->nmIcon == nil)
  3447.         {
  3448.             // get an icon to flash
  3449.             err = GetIconSuite(&hRes, kAppIconSuiteID, svAllSmallData);
  3450.             if ((err == noErr) && (hRes != nil))
  3451.             {
  3452.                 curAttributes = GetResAttrs(hRes);
  3453.                 if (curAttributes & resPurgeable)
  3454.                     HNoPurge(hRes);
  3455.                 pNMRec->nmIcon = hRes;
  3456.             }
  3457.             else
  3458.                 pNMRec->nmIcon = nil;
  3459.         }
  3460.     }
  3461.     else if (pNMRec->nmIcon != nil)
  3462.     {
  3463.         DisposeIconSuite(pNMRec->nmIcon, false);
  3464.         pNMRec->nmIcon = nil;
  3465.     }
  3466.     
  3467. /*
  3468.     *** JKl - do the dialog ourselves so we can continue processing in the background,
  3469.     *** this code uses notification manager for dialog.
  3470.     *** Need to post dialog needed message and display dialog if we are in background.
  3471.     *** HandleReceive displays the dialog once receive is complete.
  3472.     if (notifyPrefs & kNotifyAlert)
  3473.     {
  3474.         if (pNMRec->nmStr == nil)
  3475.         {
  3476.             // get an alert string
  3477.             hRes = GetResource('STR ', kNotifyString);
  3478.             pNMRec->nmStr = (StringPtr) NewPtr(**hRes + 1);
  3479.             if (pNMRec->nmStr != nil)
  3480.                 BlockMove(*hRes, pNMRec->nmStr, **hRes + 1);
  3481.             ReleaseResource(hRes);
  3482.         }
  3483.     }
  3484.     else if (pNMRec->nmStr != nil)
  3485.     {
  3486.         DisposePtr((Ptr) pNMRec->nmStr);
  3487.         pNMRec->nmStr = nil;
  3488.     }
  3489. */
  3490. /*
  3491.     *** JKL - just play the sound our selves, this code uses the notification manager to make the sound
  3492.     *** HandleReceive now plays the sound once receive is complete    
  3493.     if (notifyPrefs & kNotifySound)
  3494.     {
  3495.         if (pNMRec->nmSound == nil)
  3496.         {
  3497.             // get the sound to play
  3498.             hRes = GetNamedResource('snd ', gpFWXAppData->fwixNotifySound);
  3499.             if (hRes != nil)
  3500.             {
  3501.                 curAttributes = GetResAttrs(hRes);
  3502.                 if (curAttributes & resPurgeable)
  3503.                     HNoPurge(hRes);
  3504.                 pNMRec->nmSound = hRes;
  3505.             }
  3506.             else
  3507.                 pNMRec->nmSound = (Handle) -1;        // at least play the system alert
  3508.         }
  3509.     } else if (pNMRec->nmSound != nil) {
  3510.         ReleaseResource(pNMRec->nmSound);
  3511.         pNMRec->nmSound = nil;
  3512.     }
  3513. */
  3514. }
  3515.     
  3516. //////////////////////////////////////////////////////////////////////////////
  3517. //
  3518. //    HandleNotifyResponse
  3519. //
  3520. //    Handle notification manager response
  3521. //
  3522. pascal void HandleNotifyResponse (
  3523.     NMRecPtr            pNMRequest)
  3524. {
  3525.     if (gpFWXAppData->inForeground) {
  3526.         NMRemove(pNMRequest);
  3527.         pNMRequest->nmRefCon = kNoNotificationPosted;
  3528.     }
  3529. }
  3530.  
  3531. //////////////////////////////////////////////////////////////////////////////
  3532. //
  3533. //    FWXInit
  3534. //
  3535. //    Initialization routine for FWX
  3536. //
  3537. static OSErr FWXInit(void)
  3538. {
  3539.     Handle            hString;
  3540.     SInt16            curResFile;
  3541.     SInt16            itemHit;
  3542.     OSErr            err = noErr;
  3543.     
  3544.     // Create global data record
  3545.     gpFWXAppData = (FWXAppDataPtr)
  3546.         NewPtrClear(sizeof (FWXAppData));
  3547.     if (gpFWXAppData == nil)
  3548.         err = memFullErr;
  3549.  
  3550.     if (err == noErr) {
  3551.         gpFWXAppData->quitFlag = false;
  3552.         gpFWXAppData->inForeground = true;
  3553.         gpFWXAppData->fwxClientID = kInvalidFWXClientID;
  3554.         gpFWXAppData->pSenderWindow = nil;
  3555.         
  3556.         gCheckingTransfer = false;
  3557.         gSendingFile = false;
  3558.         gSendingDataFork = false;
  3559.         gSendingResFork = false;
  3560.         gForkComplete = true;
  3561.         gForkWriteComplete = true;
  3562.         gSendError = (FWXNodeID) 0;
  3563.         gReceiveError = (FWXNodeID) 0;
  3564.         
  3565.         InitGraf(&qd.thePort);
  3566.         InitFonts();
  3567.         InitWindows();
  3568.         InitMenus();
  3569.         TEInit();
  3570.         InitDialogs(nil);
  3571.         InitCursor();
  3572.             
  3573.         // Make sure there is a sharing setup macintosh name
  3574.         curResFile = CurResFile();
  3575.         UseResFile(kSystemResFile);
  3576.         hString = Get1Resource('STR ', kNetworkNameID);
  3577.         UseResFile(curResFile);
  3578.         if ((hString == nil) || (**hString == 0))
  3579.         {
  3580.             // no name or string is empty
  3581.             itemHit = HandleStopAlert(kNoNameAlertID);
  3582.             if (itemHit == kOKButton)
  3583.                 OpenSharingSetup();
  3584.             ExitToShell();
  3585.         }
  3586.  
  3587.         if (err == noErr)
  3588.             err = SetupIOQueue();
  3589.         if (err == noErr)
  3590.             err = InstallAppleEventHandlers();
  3591.         if (err == noErr)
  3592.             err = InstallCompletionRoutineProcs();
  3593.         if (err == noErr)
  3594.             err = CreateMenus();
  3595.         if (err == noErr)
  3596.             err = InitPrefs();
  3597.         if (err == noErr)
  3598.             err = NewSenderWindow();
  3599.         if (err == noErr)
  3600.             err = InstallDragHandlers();
  3601.         if (err == noErr)
  3602.             err = SetupFWXNode();
  3603.         if (err == noErr)
  3604.             err = InitNotification();
  3605.     }
  3606.     return err;
  3607. }            
  3608.     
  3609. //////////////////////////////////////////////////////////////////////////////
  3610. //
  3611. //    FWXDispose
  3612. //
  3613. //    Disposal routine for FWX
  3614. //
  3615. static OSErr FWXDispose(void)
  3616. {
  3617.     IOParamPtr        pIOPb;
  3618.     OSErr            err = noErr;
  3619.  
  3620.     // dispose of file write parameter blocks and write queue
  3621.     //zzz must ensure that none are still pending
  3622.  
  3623.     // dispose of FW control parameter blocks and write queue
  3624.     //zzz must ensure that none are still pending
  3625.     if (queuesInitialized) {
  3626.         pIOPb = (IOParamPtr) gFWControlQHdr.qHead;
  3627.         while (pIOPb) {
  3628.             Dequeue ((QElemPtr) pIOPb, &gFWControlQHdr);
  3629.             UnholdMemory (pIOPb->ioBuffer, kFWControlParamBufferSize);
  3630.             DisposePtr (pIOPb->ioBuffer);
  3631.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  3632.             DisposePtr ((Ptr) pIOPb);
  3633.  
  3634.             pIOPb = (IOParamPtr) gFWControlQHdr.qHead;
  3635.         }
  3636.     }
  3637.  
  3638.     // dispose of file read parameter blocks and write queue
  3639.     //zzz must ensure that none are still pending
  3640.     if (queuesInitialized) {
  3641.         pIOPb = (IOParamPtr) gFileReadQHdr.qHead;
  3642.         while (pIOPb) {
  3643.             Dequeue ((QElemPtr) pIOPb, &gFileReadQHdr);
  3644.             UnholdMemory (pIOPb->ioBuffer, kFileReadBufSize);
  3645.             DisposePtr (pIOPb->ioBuffer);
  3646.             UnholdMemory ((Ptr) pIOPb, sizeof(IOParam));
  3647.             DisposePtr ((Ptr) pIOPb);
  3648.  
  3649.             pIOPb = (IOParamPtr) gFileReadQHdr.qHead;
  3650.         }
  3651.     }
  3652.  
  3653.     if (gpFWXAppData != nil) {
  3654.         // Unregister as a client of FWiX.
  3655.         if (gpFWXAppData->fwxClientID != (FWXClientID) kInvalidFWXClientID)
  3656.             UnregisterFWXClientApplication (gpFWXAppData->fwxClientID);
  3657.  
  3658.         // Deallocate our globals.
  3659.         DisposePtr ((Ptr) gpFWXAppData);
  3660.         gpFWXAppData = nil;
  3661.     }
  3662.  
  3663.     return err;    
  3664. }
  3665.